diff options
Diffstat (limited to 'compiler/rustc_middle')
| -rw-r--r-- | compiler/rustc_middle/src/hir/map/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/erase.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/query/mod.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/adt.rs | 19 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/mod.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/typeck_results.rs | 19 |
7 files changed, 78 insertions, 6 deletions
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 50817dd0a80..8e1cb6a514f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -756,6 +756,13 @@ impl<'hir> Map<'hir> { } } + pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> { + match self.tcx.hir_node(id) { + Node::Field(field) => field, + _ => bug!("expected field, found {}", self.node_to_string(id)), + } + } + pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner_node(id) { OwnerNode::ForeignItem(item) => item, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a272a51f327..7039749b1b7 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -238,6 +238,7 @@ trivial! { Option<rustc_span::def_id::DefId>, Option<rustc_span::def_id::LocalDefId>, Option<rustc_span::Span>, + Option<rustc_target::abi::FieldIdx>, Option<rustc_target::spec::PanicStrategy>, Option<usize>, Result<(), rustc_errors::ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 938fba0ed09..e9f61a54270 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2217,6 +2217,10 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } + + query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> { + desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 685c3e87dac..d07a53ee679 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -50,6 +50,8 @@ bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; + /// Indicates whether the type is anonymous. + const IS_ANONYMOUS = 1 << 10; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -233,8 +235,12 @@ impl AdtDefData { kind: AdtKind, variants: IndexVec<VariantIdx, VariantDef>, repr: ReprOptions, + is_anonymous: bool, ) -> Self { - debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); + debug!( + "AdtDef::new({:?}, {:?}, {:?}, {:?}, {:?})", + did, kind, variants, repr, is_anonymous + ); let mut flags = AdtFlags::NO_ADT_FLAGS; if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) { @@ -267,6 +273,9 @@ impl AdtDefData { if Some(did) == tcx.lang_items().unsafe_cell_type() { flags |= AdtFlags::IS_UNSAFE_CELL; } + if is_anonymous { + flags |= AdtFlags::IS_ANONYMOUS; + } AdtDefData { did, variants, flags, repr } } @@ -365,6 +374,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } + /// Returns `true` if this is an anonymous adt + #[inline] + pub fn is_anonymous(self) -> bool { + self.flags().contains(AdtFlags::IS_ANONYMOUS) + } + /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() @@ -386,7 +401,7 @@ impl<'tcx> AdtDef<'tcx> { } /// Returns an iterator over all fields contained - /// by this ADT. + /// by this ADT (nested unnamed fields are not expanded). #[inline] pub fn all_fields(self) -> impl Iterator<Item = &'tcx FieldDef> + Clone { self.variants().iter().flat_map(|v| v.fields.iter()) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b747f0a4fb6..9a0eea6592f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -715,8 +715,16 @@ impl<'tcx> TyCtxt<'tcx> { kind: AdtKind, variants: IndexVec<VariantIdx, ty::VariantDef>, repr: ReprOptions, + is_anonymous: bool, ) -> ty::AdtDef<'tcx> { - self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr)) + self.mk_adt_def_from_data(ty::AdtDefData::new( + self, + did, + kind, + variants, + repr, + is_anonymous, + )) } /// Allocates a read-only byte or string literal for `mir::interpret`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c9137f374a2..e73b9836174 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1130,6 +1130,8 @@ bitflags! { /// Indicates whether this variant was obtained as part of recovering from /// a syntactic error. May be incomplete or bogus. const IS_RECOVERED = 1 << 1; + /// Indicates whether this variant has unnamed fields. + const HAS_UNNAMED_FIELDS = 1 << 2; } } rustc_data_structures::external_bitflags_debug! { VariantFlags } @@ -1143,7 +1145,7 @@ pub struct VariantDef { /// `DefId` that identifies the variant's constructor. /// If this variant is a struct variant, then this is `None`. pub ctor: Option<(CtorKind, DefId)>, - /// Variant or struct name. + /// Variant or struct name, maybe empty for anonymous adt (struct or union). pub name: Symbol, /// Discriminant of this variant. pub discr: VariantDiscr, @@ -1180,11 +1182,12 @@ impl VariantDef { parent_did: DefId, recovered: bool, is_field_list_non_exhaustive: bool, + has_unnamed_fields: bool, ) -> Self { debug!( "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?}, - fields = {:?}, adt_kind = {:?}, parent_did = {:?})", - name, variant_did, ctor, discr, fields, adt_kind, parent_did, + fields = {:?}, adt_kind = {:?}, parent_did = {:?}, has_unnamed_fields = {:?})", + name, variant_did, ctor, discr, fields, adt_kind, parent_did, has_unnamed_fields, ); let mut flags = VariantFlags::NO_VARIANT_FLAGS; @@ -1196,6 +1199,10 @@ impl VariantDef { flags |= VariantFlags::IS_RECOVERED; } + if has_unnamed_fields { + flags |= VariantFlags::HAS_UNNAMED_FIELDS; + } + VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags } } @@ -1211,6 +1218,12 @@ impl VariantDef { self.flags.intersects(VariantFlags::IS_RECOVERED) } + /// Does this variant contains unnamed fields + #[inline] + pub fn has_unnamed_fields(&self) -> bool { + self.flags.intersects(VariantFlags::HAS_UNNAMED_FIELDS) + } + /// Computes the `Ident` of this variant by looking up the `Span` pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) @@ -1374,6 +1387,11 @@ impl<'tcx> FieldDef { pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.did).unwrap()) } + + /// Returns whether the field is unnamed + pub fn is_unnamed(&self) -> bool { + self.name == rustc_span::symbol::kw::Underscore + } } #[derive(Debug, PartialEq, Eq)] diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index ad41a674dd8..be91474b988 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -44,6 +44,12 @@ pub struct TypeckResults<'tcx> { /// belongs, but it may not exist if it's a tuple field (`tuple.0`). field_indices: ItemLocalMap<FieldIdx>, + /// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded + /// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type + /// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of + /// `_(2).field`. + nested_fields: ItemLocalMap<Vec<(Ty<'tcx>, FieldIdx)>>, + /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated outside inference. See /// typeck::check::fn_ctxt for details. @@ -214,6 +220,7 @@ impl<'tcx> TypeckResults<'tcx> { hir_owner, type_dependent_defs: Default::default(), field_indices: Default::default(), + nested_fields: Default::default(), user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), @@ -285,6 +292,18 @@ impl<'tcx> TypeckResults<'tcx> { self.field_indices().get(id).cloned() } + pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields } + } + + pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields } + } + + pub fn nested_field_tys_and_indices(&self, id: hir::HirId) -> &[(Ty<'tcx>, FieldIdx)] { + self.nested_fields().get(id).map_or(&[], Vec::as_slice) + } + pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types } } |
