diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e8731cf20f28b..5d88c2a0ab6af 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2093,6 +2093,8 @@ pub enum TyKind { /// generate `NodeId`s on the fly, which would complicate /// the generation of opaque `type Foo = impl Trait` items significantly. ImplTrait(NodeId, GenericBounds), + /// `field_of!($ty, $field)` type. + FieldInfo(P, Ident), /// No-op; kept solely so that we can pretty-print faithfully. Paren(P), /// Unused for now. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 8ce86bf9ecf52..eb20fb817613c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -513,6 +513,10 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { vis.visit_id(id); visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } + TyKind::FieldInfo(container, field) => { + vis.visit_ty(container); + vis.visit_ident(field); + } TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => { fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 9dbadcb49d3fc..28c2523ed0444 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -437,6 +437,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::ImplTrait(_, bounds) => { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } + TyKind::FieldInfo(container, field) => { + visitor.visit_ty(container); + visitor.visit_ident(*field); + } TyKind::Typeof(expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::MacCall(mac) => visitor.visit_mac_call(mac), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index aa8ad9784513d..8794ddd667cfc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1373,6 +1373,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Path(qself, path) => { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); } + TyKind::FieldInfo(container, field) => { + hir::TyKind::FieldInfo(self.lower_ty(container, itctx), self.lower_ident(*field)) + } TyKind::ImplicitSelf => { let hir_id = self.next_id(); let res = self.expect_full_res(t.id); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cbdcc683b566d..ce3f42ad9fb05 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1003,6 +1003,14 @@ impl<'a> State<'a> { self.word_nbsp("impl"); self.print_type_bounds(bounds); } + ast::TyKind::FieldInfo(container, field) => { + self.word("builtin # field_of!"); + self.popen(); + self.print_type(container); + self.word(","); + self.print_ident(*field); + self.pclose(); + } ast::TyKind::Array(ty, length) => { self.word("["); self.print_type(ty); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3d3fd412ae0d1..4d9bce255f34f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1621,7 +1621,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) - | ty::Placeholder(_) => { + | ty::Placeholder(_) + | ty::FieldInfo(..) => { bug!("When Place is Deref it's type shouldn't be {place_ty:#?}") } }, @@ -1658,7 +1659,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) - | ty::Placeholder(_) => bug!( + | ty::Placeholder(_) + | ty::FieldInfo(..) => bug!( "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" ), }, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 8630e5623e168..be05c32904aae 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -426,7 +426,8 @@ fn push_debuginfo_type_name<'tcx>( | ty::Placeholder(..) | ty::Alias(..) | ty::Bound(..) - | ty::CoroutineWitness(..) => { + | ty::CoroutineWitness(..) + | ty::FieldInfo(..) => { bug!( "debuginfo: Trying to create type name for \ unexpected type: {:?}", diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 854fe9a0765f3..18921e7bf9abe 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -173,7 +173,8 @@ pub(crate) fn const_to_valtree_inner<'tcx>( // FIXME(oli-obk): we can probably encode closures just like structs | ty::Closure(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType), + | ty::CoroutineWitness(..) + | ty::FieldInfo(..) => Err(ValTreeCreationError::NonSupportedType), } } @@ -306,7 +307,8 @@ pub fn valtree_to_const_value<'tcx>( | ty::FnPtr(_) | ty::Str | ty::Slice(_) - | ty::Dynamic(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()), + | ty::Dynamic(..) + | ty::FieldInfo(..) => bug!("no ValTree should have been created for type {:?}", ty.kind()), } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 04e5b550d6d9b..1d590c0ef57e6 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1013,7 +1013,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::Array(..) | ty::Closure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::FieldInfo(..) => true, ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c29f23b913f68..e231e2068d987 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -89,7 +89,8 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::Error(_) => ConstValue::from_target_usize(0u64, &tcx), + | ty::Error(_) + | ty::FieldInfo(..) => ConstValue::from_target_usize(0u64, &tcx), }, other => bug!("`{}` is not a zero arg intrinsic", other), }) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 20f251d5c91ad..1a7d5d02cd76c 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -580,7 +580,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) - | ty::Coroutine(..) => Ok(false), + | ty::Coroutine(..) + | ty::FieldInfo(..) => Ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty::Error(_) diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index a82b65b19a882..11598b3b2d8b1 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -38,7 +38,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnPtr(_) | ty::Never | ty::Tuple(_) - | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), + | ty::Dynamic(_, _, _) + | ty::FieldInfo(..) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 258d6710bc57f..8a5d7640343d5 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -116,6 +116,8 @@ pub enum DefKind { of_trait: bool, }, Closure, + /// Field Representing type from `field_of!`. + FieldInfo, } impl DefKind { @@ -160,6 +162,7 @@ impl DefKind { DefKind::Closure => "closure", DefKind::ExternCrate => "extern crate", DefKind::GlobalAsm => "global assembly block", + DefKind::FieldInfo => "field info type", } } @@ -197,7 +200,8 @@ impl DefKind { | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy - | DefKind::TyParam => Some(Namespace::TypeNS), + | DefKind::TyParam + | DefKind::FieldInfo => Some(Namespace::TypeNS), DefKind::Fn | DefKind::Const @@ -236,7 +240,8 @@ impl DefKind { | DefKind::TraitAlias | DefKind::AssocTy | DefKind::TyParam - | DefKind::ExternCrate => DefPathData::TypeNs(name), + | DefKind::ExternCrate + | DefKind::FieldInfo => DefPathData::TypeNs(name), DefKind::Fn | DefKind::Const | DefKind::ConstParam @@ -295,7 +300,8 @@ impl DefKind { | DefKind::AnonConst | DefKind::InlineConst | DefKind::GlobalAsm - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::FieldInfo => false, } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 81733d8f64e2c..c82db4675823f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2542,6 +2542,8 @@ pub enum TyKind<'hir> { /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), + /// `field_of!($ty, $field)`. + FieldInfo(&'hir Ty<'hir>, Ident), /// Unused for now. Typeof(AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 963b324ca1339..d8a313627fa8b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -860,6 +860,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } visitor.visit_lifetime(lifetime); } + TyKind::FieldInfo(container, field) => { + visitor.visit_ty(container); + visitor.visit_ident(field); + } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::Err(_) => {} } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index fd3e6bd44e794..c00cccae02f7d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2538,6 +2538,31 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); tcx.at(span).type_of(def_id).instantiate(tcx, args) } + hir::TyKind::FieldInfo(container, field) => { + let span = container.span; + let container = self.ast_ty_to_ty(container); + match container.kind() { + ty::Adt(adt_def, args) if adt_def.is_struct() => { + if let Some(field_def) = adt_def + .non_enum_variant() + .fields + .iter() + .find(|f| f.ident(tcx) == *field) + { + tcx.type_of(field_def.field_repr).instantiate(tcx, args) + } else { + Ty::new_error( + tcx, + tcx.sess.err(format!("field `{field:?}` not found.")), + ) + } + } + _ => Ty::new_error( + tcx, + tcx.sess.span_err(span, format!("`field_of!` only supports structs.")), + ), + } + } hir::TyKind::Array(ty, length) => { let length = match length { &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 1b4df31b50c70..5b3c861610ff0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -130,6 +130,7 @@ impl<'tcx> InherentCollect<'tcx> { let self_ty = self.tcx.type_of(id).instantiate_identity(); match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), + ty::FieldInfo(def, ..) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), ty::Dynamic(data, ..) if data.principal_def_id().is_some() => { self.check_def_id(id, self_ty, data.principal_def_id().unwrap()); diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 451004576292a..6bbadd0cca271 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -172,6 +172,14 @@ fn do_orphan_check_impl<'tcx>( NonlocalImpl::DisallowBecauseNonlocal }, ), + ty::FieldInfo(def, ..) => ( + LocalImpl::Allow, + if def.container().is_local() { + NonlocalImpl::Allow + } else { + NonlocalImpl::DisallowBecauseNonlocal + }, + ), // extern { type OpaqueType; } // impl AutoTrait for OpaqueType {} diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0a1b8c8eea58a..5f9f9a79c3e19 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -75,6 +75,7 @@ pub fn provide(providers: &mut Providers) { type_param_predicates: predicates_of::type_param_predicates, trait_def, adt_def, + field_info_def, fn_sig, impl_trait_ref, impl_polarity, @@ -781,6 +782,26 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } +fn convert_field_repr( + tcx: TyCtxt<'_>, + f: &hir::FieldDef<'_>, + parent_did: LocalDefId, + ident: Ident, +) -> DefId { + let field_repr = tcx.at(f.span).create_def( + f.def_id, + Symbol::intern(&format!("{ident:?}->{:?}", f.ident)), + DefKind::FieldInfo, + ); + field_repr.opt_local_def_id_to_hir_id(None); + field_repr.def_ident_span(Some(f.span)); + field_repr.visibility(tcx.visibility(f.def_id)); + field_repr.generics_of(tcx.generics_of(parent_did).clone()); + field_repr.inferred_outlives_of(&[]); + //field_repr.type_of(); + field_repr.def_id().to_def_id() +} + fn convert_variant( tcx: TyCtxt<'_>, variant_did: Option, @@ -805,8 +826,9 @@ fn convert_variant( } else { seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } - + let field_repr = convert_field_repr(tcx, f, parent_did, ident); ty::FieldDef { + field_repr, did: f.def_id.to_def_id(), name: f.ident.name, vis: tcx.visibility(f.def_id), @@ -893,6 +915,13 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr) } +fn field_info_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::FieldInfoDef<'_> { + let parent_field = tcx.parent(def_id.to_def_id()); + let field_hir = tcx.local_def_id_to_hir_id(parent_field.as_local().unwrap()); + let item_id = tcx.hir().get_parent_item(field_hir); + tcx.mk_field_info_def(def_id.to_def_id(), item_id.def_id.to_def_id()) +} + fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let item = tcx.hir().expect_item(def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ca9443225e294..7acea6d8c5312 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -502,6 +502,13 @@ pub(super) fn explicit_predicates_of<'tcx>( } } } else { + if matches!(def_kind, DefKind::FieldInfo) { + let parent = tcx.parent(def_id.to_def_id()); + let parent_hir_id = tcx.local_def_id_to_hir_id(parent.as_local().unwrap()); + let item_def_id = tcx.hir().get_parent_item(parent_hir_id); + + return tcx.explicit_predicates_of(item_def_id); + } if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs { let hir_id = tcx.local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c4fc4dda069aa..54343ff3d92f7 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -350,6 +350,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder ConstraintContext<'a, 'tcx> { self.add_constraints_from_sig(current, sig, variance); } + ty::FieldInfo(_, args) => { + self.add_constraints_from_invariant_args(current, args, variance); + } + ty::Error(_) => { // we encounter this when walking the trait references for object // types, where we use Error as the Self type diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 410706110c96e..80417003d6ef5 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -61,6 +61,14 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } + DefKind::FieldInfo => { + // These are inferred. + let crate_map = tcx.crate_variances(()); + let parent_field = tcx.parent(item_def_id.to_def_id()); + let field_hir = tcx.local_def_id_to_hir_id(parent_field.as_local().unwrap()); + let parent_struct = tcx.hir().get_parent_item(field_hir); + return crate_map.variances.get(&parent_struct.to_def_id()).copied().unwrap_or(&[]); + } DefKind::OpaqueTy => { return variance_of_opaque(tcx, item_def_id); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b7e7d258a9047..a242e3e95a9bf 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -310,6 +310,13 @@ impl<'a> State<'a> { self.print_array_length(length); self.word("]"); } + hir::TyKind::FieldInfo(container, field) => { + self.word("field_of!"); + self.popen(); + self.print_type(container); + self.print_ident(field); + self.pclose(); + } hir::TyKind::Typeof(ref e) => { self.word("typeof("); self.print_anon_const(e); diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index d89af297560b4..b3fe1d0249f69 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -138,7 +138,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Adt(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => { + | ty::Error(_) + | ty::FieldInfo(..) => { let reported = self .tcx .sess diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 473a3965885fe..60abcc3aac15f 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -474,7 +474,8 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { | ty::Tuple(..) | ty::Alias(..) | ty::Foreign(..) - | ty::Param(..) => { + | ty::Param(..) + | ty::FieldInfo(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) } else { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 45df22d44e810..947cb6202be72 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -173,6 +173,7 @@ fn compute_components<'tcx>( ty::Float(..) | // OutlivesScalar ty::Never | // ... ty::Adt(..) | // OutlivesNominalType + ty::FieldInfo(..) | // OutlivesNominalType ty::Foreign(..) | // OutlivesNominalType ty::Str | // OutlivesScalar (ish) ty::Slice(..) | // ... diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index bae63ae171645..11ef843321fbd 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1275,7 +1275,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Placeholder(..) - | ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), + | ty::FnDef(..) + | ty::FieldInfo(..) => bug!("unexpected type in foreign function: {:?}", ty), } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 5725a759fef80..a50ab31ca607a 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1093,6 +1093,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.get_associated_item_or_field_def_ids(index) .map(|did| ty::FieldDef { did, + field_repr: self.local_def_id( + self.root + .tables + .field_info_def_ids + .get(self, did.index) + .unwrap() + .decode(self), + ), name: self.item_name(did.index), vis: self.get_visibility(did.index), }) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ffb2375a7349b..0fea718ee12e0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -856,7 +856,8 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::OpaqueTy | DefKind::Field | DefKind::Impl { .. } - | DefKind::Closure => true, + | DefKind::Closure + | DefKind::FieldInfo => true, DefKind::ForeignMod | DefKind::GlobalAsm => false, } } @@ -896,7 +897,8 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::LifetimeParam - | DefKind::GlobalAsm => false, + | DefKind::GlobalAsm + | DefKind::FieldInfo => false, } } @@ -931,7 +933,8 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Closure => false, + | DefKind::Closure + | DefKind::FieldInfo => false, } } @@ -954,7 +957,8 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::AssocFn | DefKind::AssocConst | DefKind::Macro(..) - | DefKind::Field => true, + | DefKind::Field + | DefKind::FieldInfo => true, DefKind::Use | DefKind::ForeignMod | DefKind::TyParam @@ -1001,7 +1005,8 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::FieldInfo => false, } } @@ -1072,7 +1077,8 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::OpaqueTy | DefKind::Fn | DefKind::Ctor(..) - | DefKind::AssocFn => true, + | DefKind::AssocFn + | DefKind::FieldInfo => true, DefKind::Mod | DefKind::Field | DefKind::AssocTy @@ -1121,7 +1127,8 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::Field | DefKind::TyParam - | DefKind::Closure => true, + | DefKind::Closure + | DefKind::FieldInfo => true, DefKind::Mod | DefKind::ForeignMod | DefKind::ConstParam @@ -1152,7 +1159,8 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::Closure | DefKind::ConstParam | DefKind::AnonConst - | DefKind::InlineConst => true, + | DefKind::InlineConst + | DefKind::FieldInfo => true, DefKind::OpaqueTy => { let origin = tcx.opaque_type_origin(def_id); @@ -1223,7 +1231,8 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::FieldInfo => false, } } @@ -1260,7 +1269,8 @@ fn should_encode_constness(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::FieldInfo => false, } } @@ -1293,7 +1303,8 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::Use | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::ExternCrate => false, + | DefKind::ExternCrate + | DefKind::FieldInfo => false, } } @@ -1530,6 +1541,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert!(f.did.is_local()); f.did.index })); + for f in variant.fields.iter() { + record!(self.tables.field_info_def_ids[f.did] <- f.field_repr.index) + } if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor { let fn_sig = tcx.fn_sig(ctor_def_id); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index ea8ef50460e58..1916aa1333618 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -405,6 +405,7 @@ define_tables! { // so we can take their names, visibilities etc from other encoded tables. module_children_non_reexports: Table>, associated_item_or_field_def_ids: Table>, + field_info_def_ids: Table>, def_kind: Table, visibility: Table>>, def_span: Table>, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 7cdbcd9193cf7..420b8d6536cbc 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -176,6 +176,7 @@ fixed_size_enum! { ( Macro(MacroKind::Bang) ) ( Macro(MacroKind::Attr) ) ( Macro(MacroKind::Derive) ) + ( FieldInfo ) } } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 9b41b77928e67..93e142bd0e0a2 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -12,6 +12,8 @@ macro_rules! arena_types { [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>, // AdtDef are interned and compared by address [decode] adt_def: rustc_middle::ty::AdtDefData, + // FieldInfoDef are interned and compared by address + [decode] field_info_def: rustc_middle::ty::FieldInfoDefData, [] steal_thir: rustc_data_structures::steal::Steal>, [] steal_mir: rustc_data_structures::steal::Steal>, [decode] mir: rustc_middle::mir::Body<'tcx>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cdde6a596a80e..609fe6d103683 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -333,6 +333,7 @@ tcx_lifetime! { rustc_middle::traits::query::type_op::ProvePredicate, rustc_middle::traits::query::type_op::Subtype, rustc_middle::ty::AdtDef, + rustc_middle::ty::FieldInfoDef, rustc_middle::ty::AliasTy, rustc_middle::ty::ClauseKind, rustc_middle::ty::ClosureTypeInfo, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 03f3ceb8d1733..a47bbab2d4c2b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -705,6 +705,11 @@ rustc_queries! { cache_on_disk_if { key.is_local() } separate_provide_extern } + query field_info_def(key: DefId) -> ty::FieldInfoDef<'tcx> { + desc { |tcx| "computing FieldInfo definition for `{}`", tcx.def_path_str(key) } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } query adt_destructor(key: DefId) -> Option { desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 1d9a25628b047..e994a90d50808 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -85,7 +85,7 @@ bitflags! { /// /// where `x` here represents the `DefId` of `S.x`. Then, the `DefId` /// can be used with [`TyCtxt::type_of()`] to get the type of the field. -#[derive(TyEncodable, TyDecodable)] +#[derive(TyEncodable, TyDecodable, Debug)] pub struct AdtDefData { /// The `DefId` of the struct, enum or union item. pub did: DefId, @@ -575,3 +575,119 @@ pub enum Representability { Representable, Infinite, } + +/// The definition of a field representation type of an Adt. +/// +/// These are all interned (by `mk_field_info_def`) into the global arena. +#[derive(TyEncodable, TyDecodable)] +pub struct FieldInfoDefData { + /// The `DefId` of the field representation type. + pub did: DefId, + /// The `DefId` of the container type, i.e. the type where the field is defined on. + container: DefId, + // The index of the represented field. + //idx: ty::FieldIdx, + // The `DefId` of the type of the field. + //field_ty: DefId, +} + +impl FieldInfoDefData { + pub(super) fn new( + did: DefId, + container: DefId, /*idx: ty::FieldIdx, field_ty: DefId*/ + ) -> Self { + Self { did, container /*, idx, field_ty*/ } + } +} + +impl PartialOrd for FieldInfoDefData { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// There should be only one FieldInfoDef for each `did`, therefore +/// it is fine to implement `Ord` only based on `did`. +impl Ord for FieldInfoDefData { + fn cmp(&self, other: &Self) -> Ordering { + self.did.cmp(&other.did) + } +} + +impl PartialEq for FieldInfoDefData { + #[inline] + fn eq(&self, other: &Self) -> bool { + // There should be only one `FieldInfoDefData` for each `def_id`, therefore + // it is fine to implement `PartialEq` only based on `def_id`. + // + // Below, we exhaustively destructure `self` and `other` so that if the + // definition of `FieldInfoDefData` changes, a compile-error will be produced, + // reminding us to revisit this assumption. + + let Self { did: self_def_id, .. } = self; + let Self { did: other_def_id, .. } = other; + + let res = self_def_id == other_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.container == other.container + /*&& self.idx == other.idx + && self.field_ty == other.field_ty*/; + assert!(deep, "FieldInfoDefData for the same def-id has differing data"); + } + + res + } +} + +impl Eq for FieldInfoDefData {} + +/// There should be only one FieldInfoDef for each `did`, therefore +/// it is fine to implement `Hash` only based on `did`. +impl Hash for FieldInfoDefData { + #[inline] + fn hash(&self, s: &mut H) { + self.did.hash(s) + } +} + +impl<'a> HashStable> for FieldInfoDefData { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + thread_local! { + static CACHE: RefCell> = Default::default(); + } + + let hash: Fingerprint = CACHE.with(|cache| { + let addr = self as *const FieldInfoDefData as usize; + let hashing_controls = hcx.hashing_controls(); + *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| { + let ty::FieldInfoDefData { did, container /*, idx, field_ty*/ } = *self; + + let mut hasher = StableHasher::new(); + did.hash_stable(hcx, &mut hasher); + container.hash_stable(hcx, &mut hasher); + /*idx.hash_stable(hcx, &mut hasher); + field_ty.hash_stable(hcx, &mut hasher);*/ + + hasher.finish() + }) + }); + + hash.hash_stable(hcx, hasher); + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)] +#[rustc_pass_by_value] +pub struct FieldInfoDef<'tcx>(pub Interned<'tcx, FieldInfoDefData>); + +impl<'tcx> FieldInfoDef<'tcx> { + pub fn did(self) -> DefId { + self.0.0.did + } + + pub fn container(self) -> DefId { + self.0.0.container + } +} diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 81cf41889d497..0290d912531ba 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -14,7 +14,7 @@ use crate::mir::{ }; use crate::traits; use crate::ty::GenericArgsRef; -use crate::ty::{self, AdtDef, Ty}; +use crate::ty::{self, AdtDef, FieldInfoDef, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; @@ -158,6 +158,12 @@ impl<'tcx, E: TyEncoder>> Encodable for AdtDef<'tcx> { } } +impl<'tcx, E: TyEncoder>> Encodable for FieldInfoDef<'tcx> { + fn encode(&self, e: &mut E) { + self.0.0.encode(e) + } +} + impl<'tcx, E: TyEncoder>> Encodable for AllocId { fn encode(&self, e: &mut E) { e.encode_alloc_id(self) @@ -367,6 +373,12 @@ impl<'tcx, D: TyDecoder>> Decodable for AdtDef<'tcx> { } } +impl<'tcx, D: TyDecoder>> Decodable for FieldInfoDef<'tcx> { + fn decode(decoder: &mut D) -> Self { + decoder.interner().mk_field_info_def_from_data(Decodable::decode(decoder)) + } +} + impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8e71327f82e53..963c27c58c3db 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,10 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, - ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, - PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, - TypeAndMut, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, FieldInfoDef, + FieldInfoDefData, GenericParamDefKind, ImplPolarity, List, ParamConst, ParamTy, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions, + TraitObjectVisitor, Ty, TyKind, TyVid, TypeAndMut, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -81,6 +81,7 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type AdtDef = ty::AdtDef<'tcx>; + type FieldInfoDef = ty::FieldInfoDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArg = ty::GenericArg<'tcx>; type Term = ty::Term<'tcx>; @@ -156,6 +157,7 @@ pub struct CtxtInterners<'tcx> { bound_variable_kinds: InternedSet<'tcx, List>, layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, + field_info_def: InternedSet<'tcx, FieldInfoDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, @@ -183,6 +185,7 @@ impl<'tcx> CtxtInterners<'tcx> { bound_variable_kinds: Default::default(), layout: Default::default(), adt_def: Default::default(), + field_info_def: Default::default(), external_constraints: Default::default(), predefined_opaques_in_body: Default::default(), fields: Default::default(), @@ -686,6 +689,10 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr)) } + pub fn mk_field_info_def(self, did: DefId, container: DefId) -> ty::FieldInfoDef<'tcx> { + self.mk_field_info_def_from_data(ty::FieldInfoDefData::new(did, container)) + } + /// Allocates a read-only byte or string literal for `mir::interpret`. pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { // Create an allocation that just contains these bytes. @@ -1450,6 +1457,7 @@ impl<'tcx> TyCtxt<'tcx> { Closure, Tuple, Bound, + FieldInfo, Param, Infer, Alias, @@ -1584,6 +1592,7 @@ direct_interners! { const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, + field_info_def: pub mk_field_info_def_from_data(FieldInfoDefData): FieldInfoDef -> FieldInfoDef<'tcx>, external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>): ExternalConstraints -> ExternalConstraints<'tcx>, predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 469593fe66347..955fb6c9a0aa8 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -307,6 +307,7 @@ impl<'tcx> Ty<'tcx> { ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), ty::Bound(..) => "bound type variable".into(), + ty::FieldInfo(..) => "field info type".into(), ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(), ty::Alias(ty::Weak, _) => "type alias".into(), ty::Param(_) => "type parameter".into(), diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index f95ceeff1507a..1fd8d62914732 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -153,7 +153,7 @@ pub fn simplify_type<'tcx>( TreatParams::ForLookup | TreatParams::AsCandidateKey => None, }, ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), - ty::Bound(..) | ty::Infer(_) | ty::Error(_) => None, + ty::Bound(..) | ty::FieldInfo(..) | ty::Infer(_) | ty::Error(_) => None, } } @@ -231,7 +231,8 @@ impl DeepRejectCtxt { | ty::Never | ty::Tuple(..) | ty::FnPtr(..) - | ty::Foreign(..) => debug_assert!(impl_ty.is_known_rigid()), + | ty::Foreign(..) + | ty::FieldInfo(..) => debug_assert!(impl_ty.is_known_rigid()), ty::FnDef(..) | ty::Closure(..) | ty::Coroutine(..) @@ -274,6 +275,12 @@ impl DeepRejectCtxt { } _ => false, }, + ty::FieldInfo(obl_def, obl_args) => match k { + &ty::FieldInfo(impl_def, impl_args) => { + obl_def == impl_def && self.args_may_unify(obl_args, impl_args) + } + _ => false, + }, ty::Tuple(obl) => match k { &ty::Tuple(imp) => { obl.len() == imp.len() diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 5084fc9891349..5f6e086342af1 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -141,6 +141,10 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_BOUND); } + &ty::FieldInfo(_, args) => { + self.add_args(args); + } + &ty::Placeholder(..) => { self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index e1d1f361091b5..08a13bb3622be 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -811,6 +811,7 @@ where | ty::FnDef(..) | ty::CoroutineWitness(..) | ty::Foreign(..) + | ty::FieldInfo(..) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9feda4d205e9c..0266c012f00ba 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1914,6 +1914,7 @@ pub struct FieldDef { pub did: DefId, pub name: Symbol, pub vis: Visibility, + pub field_repr: DefId, } impl PartialEq for FieldDef { @@ -1926,9 +1927,9 @@ impl PartialEq for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did: lhs_did, name: _, vis: _ } = &self; + let Self { did: lhs_did, name: _, vis: _, field_repr: _ } = &self; - let Self { did: rhs_did, name: _, vis: _ } = other; + let Self { did: rhs_did, name: _, vis: _, field_repr: _ } = other; let res = lhs_did == rhs_did; @@ -1954,7 +1955,7 @@ impl Hash for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did, name: _, vis: _ } = &self; + let Self { did, name: _, vis: _, field_repr: _ } = &self; did.hash(s) } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 5e09154789a79..2ee05bff29898 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -274,6 +274,7 @@ fn characteristic_def_id_of_type_cached<'a>( | ty::Param(_) | ty::Infer(_) | ty::Bound(..) + | ty::FieldInfo(..) | ty::Error(_) | ty::Never | ty::Float(_) => None, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 25423348638a9..5b72f1a4ac1b3 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -704,6 +704,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { false => p!(write("{s}")), }, }, + ty::FieldInfo(def, args) => p!(print_def_path(def.did(), args)), ty::Adt(def, args) => { p!(print_def_path(def.did(), args)); } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index d7d9afc30e7ea..21e55efc21ba9 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -145,6 +145,7 @@ pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( })) } +#[instrument(level = "debug", skip(relation))] pub fn relate_args_with_variances<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, ty_def_id: DefId, @@ -557,6 +558,11 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_alias(tcx, a_kind, alias_ty)) } + (&ty::FieldInfo(a_def, a_args), &ty::FieldInfo(b_def, b_args)) if a_def == b_def => { + let args = relation.relate_item_args(a_def.did(), a_args, b_args)?; + Ok(Ty::new_field_of(tcx, a_def, args)) + } + _ => Err(TypeError::Sorts(expected_found(relation, a, b))), } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 971acda33e233..ba39e8bcaa027 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -44,6 +44,19 @@ impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> { } } +impl<'tcx> fmt::Debug for ty::FieldInfoDef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + ty::tls::with(|tcx| { + with_no_trimmed_paths!({ + let s = FmtPrinter::print_string(tcx, Namespace::TypeNS, |cx| { + cx.print_def_path(self.did(), &[]) + })?; + f.write_str(&s) + }) + }) + } +} + impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let name = ty::tls::with(|tcx| tcx.hir().name(self.var_path.hir_id)); @@ -580,6 +593,7 @@ impl<'tcx> TypeSuperFoldable> for Ty<'tcx> { } ty::Closure(did, args) => ty::Closure(did, args.try_fold_with(folder)?), ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), + ty::FieldInfo(def, args) => ty::FieldInfo(def, args.try_fold_with(folder)?), ty::Bool | ty::Char @@ -628,6 +642,7 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor), ty::Closure(_did, ref args) => args.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), + ty::FieldInfo(_, args) => args.visit_with(visitor), ty::Bool | ty::Char diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e10b5706b4848..5cd4a39da8fd1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2261,6 +2261,15 @@ impl<'tcx> Ty<'tcx> { let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args); Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, context_ty) } + + #[inline] + pub fn new_field_of( + tcx: TyCtxt<'tcx>, + def: ty::FieldInfoDef<'tcx>, + args: &'tcx GenericArgs<'tcx>, + ) -> Ty<'tcx> { + Ty::new(tcx, FieldInfo(def, args)) + } } /// Type utilities @@ -2724,7 +2733,8 @@ impl<'tcx> Ty<'tcx> { | ty::Never | ty::Tuple(_) | ty::Error(_) - | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8, + | ty::Infer(IntVar(_) | FloatVar(_)) + | ty::FieldInfo(..) => tcx.types.u8, ty::Bound(..) | ty::Placeholder(_) @@ -2759,6 +2769,7 @@ impl<'tcx> Ty<'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never + | ty::FieldInfo(..) | ty::Error(_) // Extern types have metadata = (). | ty::Foreign(..) @@ -2847,7 +2858,8 @@ impl<'tcx> Ty<'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never - | ty::Error(_) => true, + | ty::Error(_) + | ty::FieldInfo(..) => true, ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => false, @@ -2877,6 +2889,8 @@ impl<'tcx> Ty<'tcx> { match self.kind() { ty::Bool | ty::Char | ty::Never => true, + ty::FieldInfo(..) => true, + // These aren't even `Clone` ty::Str | ty::Slice(..) | ty::Foreign(..) | ty::Dynamic(..) => false, @@ -2984,6 +2998,7 @@ impl<'tcx> Ty<'tcx> { | Coroutine(_, _, _) | CoroutineWitness(..) | Never + | FieldInfo(..) | Tuple(_) => true, Error(_) | Infer(_) | Alias(_, _) | Param(_) | Bound(_, _) | Placeholder(_) => false, } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 70252a4dc67b9..a324b78945653 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1064,7 +1064,8 @@ impl<'tcx> Ty<'tcx> { | ty::RawPtr(_) | ty::FnDef(..) | ty::Error(_) - | ty::FnPtr(_) => true, + | ty::FnPtr(_) + | ty::FieldInfo(..) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze), ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), ty::Adt(..) @@ -1103,7 +1104,8 @@ impl<'tcx> Ty<'tcx> { | ty::RawPtr(_) | ty::FnDef(..) | ty::Error(_) - | ty::FnPtr(_) => true, + | ty::FnPtr(_) + | ty::FieldInfo(..) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin), ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(), ty::Adt(..) @@ -1232,7 +1234,11 @@ impl<'tcx> Ty<'tcx> { // Conservatively return `false` for all others... // Anonymous function types - ty::FnDef(..) | ty::Closure(..) | ty::Dynamic(..) | ty::Coroutine(..) => false, + ty::FnDef(..) + | ty::Closure(..) + | ty::Dynamic(..) + | ty::Coroutine(..) + | ty::FieldInfo(..) => false, // Generic or inferred types // @@ -1344,6 +1350,8 @@ pub fn needs_drop_components<'tcx>( // Foreign types can never have destructors. ty::Foreign(..) => Ok(SmallVec::new()), + ty::FieldInfo(..) => Ok(SmallVec::new()), + ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop), ty::Slice(ty) => needs_drop_components(tcx, ty), @@ -1396,7 +1404,8 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { | ty::FnDef(..) | ty::FnPtr(_) | ty::Never - | ty::Foreign(_) => true, + | ty::Foreign(_) + | ty::FieldInfo(..) => true, ty::Alias(..) | ty::Dynamic(..) diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 20bdbcb5b7bb4..35aba74d14c18 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -191,7 +191,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Closure(_, args) | ty::Coroutine(_, args, _) | ty::CoroutineWitness(_, args) - | ty::FnDef(_, args) => { + | ty::FnDef(_, args) + | ty::FieldInfo(_, args) => { stack.extend(args.iter().rev()); } ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index ccf3dc7941fed..7dbd3e8a378bf 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -164,6 +164,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) + | ty::FieldInfo(..) | ty::Placeholder(_) => { bug!("When Place is Deref it's type shouldn't be {place_ty:#?}") } @@ -199,6 +200,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Bound(_, _) | ty::Infer(_) | ty::Error(_) + | ty::FieldInfo(..) | ty::Placeholder(_) => bug!( "When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" ), diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 21b92e6d77c89..aefe1b647b456 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -697,7 +697,8 @@ fn try_write_constant<'tcx>( | ty::Placeholder(..) | ty::Closure(..) | ty::Coroutine(..) - | ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"), + | ty::Dynamic(..) + | ty::FieldInfo(..) => throw_machine_stop_str!("unsupported type"), ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(), } diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 91abbb216d662..e7b0257e31b3d 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -165,7 +165,8 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Impl { .. } => { + | DefKind::Impl { .. } + | DefKind::FieldInfo => { for param in &generics.params { debug!(?param, "(other)"); if let ty::GenericParamDefKind::Lifetime = param.kind { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index b1a57c3dfd97c..d7a035e57733b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -278,6 +278,8 @@ impl<'a> Parser<'a> { // Reference self.expect_and()?; self.parse_borrowed_pointee()? + } else if self.is_builtin() { + self.parse_ty_builtin()? } else if self.eat_keyword_noexpect(kw::Typeof) { self.parse_typeof_ty()? } else if self.eat_keyword(kw::Underscore) { @@ -442,6 +444,23 @@ impl<'a> Parser<'a> { } } + fn parse_ty_builtin(&mut self) -> PResult<'a, TyKind> { + self.parse_builtin(|this, _lo, ident| { + if ident.name == sym::field_of { + return Ok(Some(this.parse_ty_field_of()?)); + } + + Ok(None) + }) + } + + fn parse_ty_field_of(&mut self) -> PResult<'a, TyKind> { + let container = self.parse_ty()?; + self.expect(&TokenKind::Comma)?; + let field = self.parse_ident()?; + Ok(TyKind::FieldInfo(container, field)) + } + fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> { let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()); let bounds = self.parse_generic_bounds_common(allow_plus)?; diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 28354ab0986e1..0db93213d75c6 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -347,6 +347,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Path, OpaqueDef, TraitObject, + FieldInfo, Typeof, Infer, Err @@ -607,6 +608,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Path, TraitObject, ImplTrait, + FieldInfo, Paren, Typeof, Infer, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e7ec4749efe67..e8b3d42e071e8 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -282,7 +282,8 @@ where | ty::Param(..) | ty::Bound(..) | ty::Error(_) - | ty::CoroutineWitness(..) => {} + | ty::CoroutineWitness(..) + | ty::FieldInfo(..) => {} ty::Placeholder(..) | ty::Infer(..) => { bug!("unexpected type: {:?}", ty) } @@ -653,7 +654,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { | DefKind::Field | DefKind::GlobalAsm | DefKind::Impl { .. } - | DefKind::Closure => (), + | DefKind::Closure + | DefKind::FieldInfo => (), } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 65901eedb2148..ca63196ca86fa 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -944,7 +944,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { | DefKind::ForeignTy | DefKind::OpaqueTy | DefKind::TraitAlias - | DefKind::AssocTy, + | DefKind::AssocTy + | DefKind::FieldInfo, _, ) | Res::PrimTy(..) diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 202ca1b156aa7..31d1b37dccddc 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -11,8 +11,8 @@ use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::ty::{ AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, - ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span, - TraitRef, Ty, UintTy, + ExistentialTraitRef, FieldInfoDef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, + RigidTy, Span, TraitRef, Ty, UintTy, }; use stable_mir::{CrateItem, DefId}; @@ -93,7 +93,8 @@ impl<'tcx> RustcInternal<'tcx> for RigidTy { | RigidTy::Coroutine(..) | RigidTy::CoroutineWitness(..) | RigidTy::Dynamic(..) - | RigidTy::Tuple(..) => { + | RigidTy::Tuple(..) + | RigidTy::FieldInfo(..) => { todo!() } } @@ -279,6 +280,13 @@ impl<'tcx> RustcInternal<'tcx> for AdtDef { } } +impl<'tcx> RustcInternal<'tcx> for FieldInfoDef { + type T = rustc_ty::FieldInfoDef<'tcx>; + fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T { + tables.tcx.field_info_def(self.0.internal(&mut *tables)) + } +} + impl<'tcx> RustcInternal<'tcx> for Span { type T = rustc_span::Span; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index c3db9b358e8b5..49e72ff64e659 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -58,6 +58,10 @@ impl<'tcx> Tables<'tcx> { stable_mir::ty::AdtDef(self.create_def_id(did)) } + pub fn field_info_def(&mut self, did: DefId) -> stable_mir::ty::FieldInfoDef { + stable_mir::ty::FieldInfoDef(self.create_def_id(did)) + } + pub fn foreign_def(&mut self, did: DefId) -> stable_mir::ty::ForeignDef { stable_mir::ty::ForeignDef(self.create_def_id(did)) } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index f837f28e11ed2..da37d6ec7b563 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -391,6 +391,11 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { ty::Bound(debruijn_idx, bound_ty) => { TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables)) } + ty::FieldInfo(def, args) => TyKind::RigidTy(RigidTy::FieldInfo( + tables.field_info_def(def.did()), + args.stable(tables), + )), + ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness( tables.coroutine_witness_def(*def_id), args.stable(tables), diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index eee587f3b2ab1..7bb93892adb2b 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -86,7 +86,8 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind { | DefKind::LifetimeParam | DefKind::Impl { .. } | DefKind::Ctor(_, _) - | DefKind::GlobalAsm => { + | DefKind::GlobalAsm + | DefKind::FieldInfo => { unreachable!("Not a valid item kind: {kind:?}"); } DefKind::Closure | DefKind::AssocFn | DefKind::Fn => ItemKind::Fn, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d7e822382ef92..b1b20efac21b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -760,6 +760,7 @@ symbols! { ffi_returns_twice, field, field_init_shorthand, + field_of, file, float, float_to_int_unchecked, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 18ca347de97f1..486d70b8944e6 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -721,6 +721,7 @@ fn encode_ty<'tcx>( | ty::Error(..) | ty::CoroutineWitness(..) | ty::Infer(..) + | ty::FieldInfo(..) | ty::Placeholder(..) => { bug!("encode_ty: unexpected `{:?}`", ty.kind()); } @@ -972,7 +973,12 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ); } - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + ty::Bound(..) + | ty::Error(..) + | ty::Infer(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::FieldInfo(..) => { bug!("transform_ty: unexpected `{:?}`", ty.kind()); } } diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index e002e345ae689..1e6257fb8ea86 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -424,6 +424,10 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // Mangle all nominal types as paths. ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), args) + | ty::FieldInfo( + ty::FieldInfoDef(Interned(&ty::FieldInfoDefData { did: def_id, .. }, _)), + args, + ) | ty::FnDef(def_id, args) | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, args, .. }) | ty::Closure(def_id, args) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index b6861d258d1e6..2e3d1c39458c4 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -424,7 +424,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Closure(_, _) | ty::Coroutine(_, _, _) | ty::Never - | ty::Tuple(_) => { + | ty::Tuple(_) + | ty::FieldInfo(..) => { let simp = fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap(); consider_impls_for_simplified_type(simp); @@ -646,7 +647,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Alias(ty::Weak, _) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + | ty::Bound(..) + | ty::FieldInfo(..) => bug!("unexpected self type for `{goal:?}`"), // Excluding IATs and type aliases here as they don't have meaningful item bounds. ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, }; @@ -800,7 +802,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) - | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), + | ty::Bound(..) + | ty::FieldInfo(..) => bug!("unexpected self type for `{goal:?}`"), ty::Dynamic(bounds, ..) => bounds, }; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index f442e2a08a811..51a06c91610cb 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -29,7 +29,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::FnPtr(_) | ty::Error(_) | ty::Never - | ty::Char => Ok(vec![]), + | ty::Char + | ty::FieldInfo(..) => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` ty::Str => Ok(vec![Ty::new_slice(tcx, tcx.types.u8)]), @@ -130,7 +131,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Closure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => Ok(vec![]), + | ty::Error(_) + | ty::FieldInfo(..) => Ok(vec![]), ty::Str | ty::Slice(_) @@ -183,7 +185,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Adt(_, _) | ty::Alias(_, _) | ty::Param(_) - | ty::Placeholder(..) => Err(NoSolution), + | ty::Placeholder(..) + | ty::FieldInfo(..) => Err(NoSolution), ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { @@ -286,7 +289,8 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( | ty::Param(_) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::Error(_) => Err(NoSolution), + | ty::Error(_) + | ty::FieldInfo(..) => Err(NoSolution), ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs index 004dc45263c40..7e6c0f49e055a 100644 --- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs +++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs @@ -343,7 +343,8 @@ impl<'tcx> TypeFolder> for Canonicalizer<'_, 'tcx> { | ty::Tuple(_) | ty::Alias(_, _) | ty::Bound(_, _) - | ty::Error(_) => return t.super_fold_with(self), + | ty::Error(_) + | ty::FieldInfo(_, _) => return t.super_fold_with(self), }; let var = ty::BoundVar::from( diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 038235696694e..bcf46d091020e 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -395,7 +395,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Never - | ty::Foreign(..) => tcx.types.unit, + | ty::Foreign(..) + | ty::FieldInfo(..) => tcx.types.unit, ty::Error(e) => Ty::new_error(tcx, *e), @@ -601,7 +602,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { | ty::Slice(_) | ty::Dynamic(_, _, _) | ty::Tuple(_) - | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()), + | ty::Error(_) + | ty::FieldInfo(..) => self_ty.discriminant_ty(ecx.tcx()), // We do not call `Ty::discriminant_ty` on alias, param, or placeholder // types, which return `::Discriminant` diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 95712da3c5e82..87be0794c37c9 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -918,6 +918,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Never | ty::Tuple(_) | ty::Adt(_, _) + | ty::FieldInfo(..) // FIXME: Handling opaques here is kinda sus. Especially because we // simplify them to SimplifiedType::Placeholder. | ty::Alias(ty::Opaque, _) => { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8e97333ad0f3e..694b84b9d8b1c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -893,6 +893,13 @@ where self.found_non_local_ty(ty) } } + ty::FieldInfo(def, _) => { + if self.def_id_is_local(def.did()) { + ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) + } else { + self.found_non_local_ty(ty) + } + } ty::Foreign(def_id) => { if self.def_id_is_local(def_id) { ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index b3910a2770b3a..2e21e722944fd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1635,6 +1635,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Coroutine(..) => Some(18), ty::Foreign(..) => Some(19), ty::CoroutineWitness(..) => Some(20), + ty::FieldInfo(..) => Some(21), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 45bdff09deed7..64d2f7137ca3f 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1850,7 +1850,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Never | ty::Tuple(..) // Integers and floats always have `u8` as their discriminant. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) + // FieldInfo has unit metadata. + | ty::FieldInfo(..) => true, // type parameters, opaques, and unnormalized projections have pointer // metadata if they're known (e.g. by the param_env) to be sized @@ -1905,7 +1907,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // If returned by `struct_tail_without_normalization` this is the empty tuple. | ty::Tuple(..) // Integers and floats are always Sized, and so have unit type metadata. - | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, + | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) + // FieldInfo has unit metadata. + | ty::FieldInfo(..)=> true, // type parameters, opaques, and unnormalized projections have pointer // metadata if they're known (e.g. by the param_env) to be sized diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index ec80df1d658a8..ef27d797cbaf3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -70,7 +70,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Placeholder(..) | ty::Infer(_) | ty::Bound(..) - | ty::Coroutine(..) => false, + | ty::Coroutine(..) + | ty::FieldInfo(..) => false, } } @@ -325,7 +326,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( } // Types that can't be resolved. Pass them forward. - ty::Alias(..) | ty::Param(..) => { + ty::Alias(..) | ty::Param(..) | ty::FieldInfo(..) => { constraints.dtorck_types.push(ty); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index e87e585ef0b72..d6554462abfdf 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -141,6 +141,7 @@ where type Output = Q::QueryResponse; type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; + #[instrument(level = "debug", skip(infcx))] fn fully_perform( self, infcx: &InferCtxt<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 5a559bb5fa0d4..1bab7785829a0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -457,7 +457,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::Error(_) => return true, + | ty::Error(_) + | ty::FieldInfo(..) => return true, // FIXME: Function definitions could actually implement `FnPtr` by // casting the ZST function def to a function pointer. ty::FnDef(_, _) => return true, @@ -591,7 +592,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) => { + | ty::CoroutineWitness(..) + | ty::FieldInfo(..) => { // Only consider auto impls if there are no manual impls for the root of `self_ty`. // // For example, we only consider auto candidates for `&i32: Auto` if no explicit impl @@ -914,7 +916,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(ConstDestructCandidate(None)); } - ty::Adt(..) => { + ty::Adt(..) | ty::FieldInfo(..) => { let mut relevant_impl = None; self.tcx().for_each_relevant_impl( self.tcx().require_lang_item(LangItem::Drop, None), @@ -989,7 +991,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Bound(_, _) | ty::Error(_) | ty::Infer(_) - | ty::Placeholder(_) => {} + | ty::Placeholder(_) + | ty::FieldInfo(..) => {} } } @@ -1056,7 +1059,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::InferTy::FloatVar(_) | ty::InferTy::FreshIntTy(_) | ty::InferTy::FreshFloatTy(_), - ) => {} + ) + | ty::FieldInfo(..) => {} ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)) => { candidates.ambiguous = true; } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b26c781100a09..a632051866ec5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2105,6 +2105,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) + | ty::FieldInfo(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { @@ -2222,7 +2223,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { + ty::Adt(..) + | ty::Alias(..) + | ty::Param(..) + | ty::Placeholder(..) + | ty::FieldInfo(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -2280,7 +2285,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Foreign(..) | ty::Alias(ty::Projection | ty::Inherent | ty::Weak, ..) | ty::Bound(..) - | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::FieldInfo(..) => { bug!("asked to assemble constituent types of unexpected type: {:?}", t); } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index f8e47caccb7c3..0954f9e761965 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -101,6 +101,10 @@ impl<'tcx> TypeVisitor> for Search<'tcx> { return ControlFlow::Continue(()); } + ty::FieldInfo(..) => { + return ControlFlow::Break(ty); + } + ty::FnPtr(..) => { return ControlFlow::Continue(()); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3a890d70d79b3..2638414f48e24 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -609,6 +609,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // WfScalar, WfParameter, etc } + ty::FieldInfo(..) => {} + // Can only infer to `ty::Int(_) | ty::Uint(_)`. ty::Infer(ty::IntVar(_)) => {} diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index eef90dc6dac63..6ad7a0b1a55bf 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -156,7 +156,8 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Closure => ty::List::empty(), + | DefKind::Closure + | DefKind::FieldInfo => ty::List::empty(), } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 7599aa9fa41b6..5e975cf026320 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -155,7 +155,7 @@ fn layout_of_uncached<'tcx>( } // The never type. - ty::Never => tcx.mk_layout(cx.layout_of_never_type()), + ty::Never | ty::FieldInfo(..) => tcx.mk_layout(cx.layout_of_never_type()), // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 67ccfe7e78abb..a8a78f6e9c644 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -220,7 +220,8 @@ where | ty::Bound(..) | ty::Never | ty::Infer(_) - | ty::Error(_) => { + | ty::Error(_) + | ty::FieldInfo(..) => { bug!("unexpected type returned by `needs_drop_components`: {component}") } } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index db43c31ccab1c..d312be2153e6e 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -310,7 +310,8 @@ fn opaque_types_defined_by<'tcx>( | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Impl { .. } => {} + | DefKind::Impl { .. } + | DefKind::FieldInfo => {} // Closures and coroutines are type checked with their parent, so we need to allow all // opaques from the closure signature *and* from the parent body. DefKind::Closure | DefKind::InlineConst => { diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 7c0261c818f55..fd608ad6f5e06 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -94,7 +94,9 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( | DefKind::ConstParam | DefKind::Ctor(_, _) | DefKind::Field - | DefKind::LifetimeParam => { + | DefKind::LifetimeParam + // TODO(y86-dev): is this correct? + | DefKind::FieldInfo => { span_bug!( tcx.def_span(item), "{kind:?} has not seen any uses of `walk_types` yet, ping oli-obk if you'd like any help" diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 56e84b6015d46..cd496f7390ad6 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -18,7 +18,7 @@ fn sized_constraint_for_ty<'tcx>( let result = match ty.kind() { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) - | FnPtr(_) | Array(..) | Closure(..) | Coroutine(..) | Never => vec![], + | FnPtr(_) | Array(..) | Closure(..) | Coroutine(..) | Never | FieldInfo(..) => vec![], Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | CoroutineWitness(..) => { // these are never sized - return the target type diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 16508c1a2579d..c053170b48345 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -7,6 +7,7 @@ use crate::{BoundVar, DebugWithInfcx, Mutability, UniverseIndex}; pub trait Interner: Sized { type DefId: Clone + Debug + Hash + Ord; type AdtDef: Clone + Debug + Hash + Ord; + type FieldInfoDef: Clone + Debug + Hash + Ord; type GenericArgs: Clone + DebugWithInfcx diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 3d4e7f77a4f2c..b7e5b60be9fc9 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -286,6 +286,9 @@ pub enum TyKind { /// A placeholder for a type which could not be computed; this is /// propagated to avoid useless error messages. Error(I::ErrorGuaranteed), + + /// `field_of!` type. + FieldInfo(I::FieldInfoDef, I::GenericArgs), } impl TyKind { @@ -326,6 +329,7 @@ const fn tykind_discriminant(value: &TyKind) -> usize { Placeholder(_) => 23, Infer(_) => 24, Error(_) => 25, + FieldInfo(_, _) => 26, } } @@ -461,6 +465,21 @@ impl DebugWithInfcx for TyKind { Placeholder(p) => write!(f, "{p:?}"), Infer(t) => write!(f, "{:?}", this.wrap(t)), TyKind::Error(_) => write!(f, "{{type error}}"), + FieldInfo(d, s) => { + write!(f, "{d:?}")?; + let mut s = s.clone().into_iter(); + let first = s.next(); + match first { + Some(first) => write!(f, "<{:?}", first)?, + None => return Ok(()), + }; + + for arg in s { + write!(f, ", {:?}", arg)?; + } + + write!(f, ">") + } } } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 6c4fb4a775352..4325dd19ab6e4 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -277,6 +277,7 @@ pub enum RigidTy { Never, Tuple(Vec), CoroutineWitness(CoroutineWitnessDef, GenericArgs), + FieldInfo(FieldInfoDef, GenericArgs), } impl From for TyKind { @@ -423,6 +424,10 @@ crate_def! { pub CoroutineWitnessDef; } +crate_def! { + pub FieldInfoDef; +} + /// A list of generic arguments. #[derive(Clone, Debug, Eq, PartialEq)] pub struct GenericArgs(pub Vec); diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 65e42879d618b..7582c659d9874 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -156,6 +156,7 @@ impl Visitable for RigidTy { } RigidTy::Tuple(fields) => fields.visit(visitor), RigidTy::Adt(_, args) => args.visit(visitor), + RigidTy::FieldInfo(_, args) => args.visit(visitor), } } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index bf10ada0176c2..e86fcdaf09f4a 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1401,3 +1401,10 @@ pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { // The `{}` is for better error messages crate::hint::must_use({builtin # offset_of($Container, $($fields).+)}) } + +/// Gets the field type. +#[unstable(feature = "field_project", issue = "106655")] +#[allow_internal_unstable(builtin_syntax, hint_must_use)] +pub macro field_of($Container:ty, $($fields:tt).+ $(,)?) { + builtin # field_of($Container, $($fields).+) +}