Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a8b76fc

Browse files
committedDec 14, 2023
Lowering anonymous structs or unions to HIR (WIP)
1 parent c3def26 commit a8b76fc

File tree

36 files changed

+278
-173
lines changed

36 files changed

+278
-173
lines changed
 

‎compiler/rustc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2108,9 +2108,9 @@ pub enum TyKind {
21082108
/// A tuple (`(A, B, C, D,...)`).
21092109
Tup(ThinVec<P<Ty>>),
21102110
/// An anonymous struct type i.e. `struct { foo: Type }`
2111-
AnonStruct(ThinVec<FieldDef>),
2111+
AnonStruct(NodeId, ThinVec<FieldDef>),
21122112
/// An anonymous union type i.e. `union { bar: Type }`
2113-
AnonUnion(ThinVec<FieldDef>),
2113+
AnonUnion(NodeId, ThinVec<FieldDef>),
21142114
/// A path (`module::module::...::Type`), optionally
21152115
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
21162116
///

‎compiler/rustc_ast/src/mut_visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
514514
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
515515
}
516516
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
517-
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
517+
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
518+
vis.visit_id(id);
518519
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
519520
}
520521
}

‎compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
441441
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
442442
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
443443
TyKind::Never | TyKind::CVarArgs => {}
444-
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
444+
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
445445
walk_list!(visitor, visit_field_def, fields)
446446
}
447447
}

‎compiler/rustc_ast_lowering/src/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
680680
}
681681
}
682682

683-
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
683+
pub(super) fn lower_field_def(
684+
&mut self,
685+
(index, f): (usize, &FieldDef),
686+
) -> hir::FieldDef<'hir> {
684687
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
685688
let t = self.lower_path_ty(
686689
&f.ty,

‎compiler/rustc_ast_lowering/src/lib.rs

+36-12
Original file line numberDiff line numberDiff line change
@@ -1326,18 +1326,42 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13261326
TyKind::Err => {
13271327
hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered"))
13281328
}
1329-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1330-
#[allow(rustc::untranslatable_diagnostic)]
1331-
#[allow(rustc::diagnostic_outside_of_impl)]
1332-
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
1333-
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
1334-
),
1335-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1336-
#[allow(rustc::untranslatable_diagnostic)]
1337-
#[allow(rustc::diagnostic_outside_of_impl)]
1338-
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
1339-
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
1340-
),
1329+
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1330+
let def_kind = match t.kind {
1331+
TyKind::AnonStruct(..) => DefKind::Struct,
1332+
TyKind::AnonUnion(..) => DefKind::Union,
1333+
_ => unreachable!(),
1334+
};
1335+
let def_id = self.create_def(
1336+
self.current_hir_id_owner.def_id,
1337+
*def_node_id,
1338+
sym::anon,
1339+
def_kind,
1340+
t.span,
1341+
);
1342+
debug!(?def_id);
1343+
let owner_id = hir::OwnerId { def_id };
1344+
self.with_hir_id_owner(*def_node_id, |this| {
1345+
let fields = this.arena.alloc_from_iter(
1346+
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
1347+
);
1348+
let span = t.span;
1349+
let variant_data = hir::VariantData::Struct(fields, false);
1350+
let generics = hir::Generics::empty();
1351+
let kind = match &t.kind {
1352+
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1353+
_ => hir::ItemKind::Union(variant_data, generics),
1354+
};
1355+
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
1356+
ident: Ident::with_dummy_span(sym::anon),
1357+
owner_id,
1358+
kind,
1359+
span: this.lower_span(span),
1360+
vis_span: this.lower_span(span.shrink_to_lo()),
1361+
}))
1362+
});
1363+
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
1364+
}
13411365
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
13421366
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
13431367
TyKind::Ref(region, mt) => {

‎compiler/rustc_ast_passes/src/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl<'a> AstValidator<'a> {
198198
}
199199
}
200200
}
201-
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
201+
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
202202
walk_list!(self, visit_field_def, fields)
203203
}
204204
_ => visit::walk_ty(self, t),

‎compiler/rustc_ast_pretty/src/pprust/state.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -987,11 +987,11 @@ impl<'a> State<'a> {
987987
}
988988
self.pclose();
989989
}
990-
ast::TyKind::AnonStruct(fields) => {
990+
ast::TyKind::AnonStruct(_, fields) => {
991991
self.head("struct");
992992
self.print_record_struct_body(fields, ty.span);
993993
}
994-
ast::TyKind::AnonUnion(fields) => {
994+
ast::TyKind::AnonUnion(_, fields) => {
995995
self.head("union");
996996
self.print_record_struct_body(fields, ty.span);
997997
}

‎compiler/rustc_hir/src/def.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_data_structures::stable_hasher::ToStableHashKey;
88
use rustc_macros::HashStable_Generic;
99
use rustc_span::def_id::{DefId, LocalDefId};
1010
use rustc_span::hygiene::MacroKind;
11+
use rustc_span::symbol::sym;
1112
use rustc_span::Symbol;
1213

1314
use std::array::IntoIter;
@@ -225,6 +226,7 @@ impl DefKind {
225226

226227
pub fn def_path_data(self, name: Symbol) -> DefPathData {
227228
match self {
229+
DefKind::Struct | DefKind::Union if name == sym::anon => DefPathData::AnonAdt,
228230
DefKind::Mod
229231
| DefKind::Struct
230232
| DefKind::Union

‎compiler/rustc_hir/src/definitions.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ pub enum DefPathData {
282282
/// An existential `impl Trait` type node.
283283
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
284284
OpaqueTy,
285+
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
286+
AnonAdt,
285287
}
286288

287289
impl Definitions {
@@ -404,8 +406,9 @@ impl DefPathData {
404406
match *self {
405407
TypeNs(name) if name == kw::Empty => None,
406408
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
409+
407410
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
408-
| OpaqueTy => None,
411+
| OpaqueTy | AnonAdt => None,
409412
}
410413
}
411414

@@ -426,6 +429,7 @@ impl DefPathData {
426429
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
427430
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
428431
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
432+
AnonAdt => DefPathDataName::Anon { namespace: sym::anon },
429433
}
430434
}
431435
}

‎compiler/rustc_hir/src/hir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,8 @@ pub enum TyKind<'hir> {
25432543
Never,
25442544
/// A tuple (`(A, B, C, D, ...)`).
25452545
Tup(&'hir [Ty<'hir>]),
2546+
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
2547+
AnonAdt(ItemId),
25462548
/// A path to a type definition (`module::module::...::Type`), or an
25472549
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
25482550
///

‎compiler/rustc_hir/src/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
862862
}
863863
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
864864
TyKind::Infer | TyKind::Err(_) => {}
865+
TyKind::AnonAdt(item_id) => {
866+
visitor.visit_nested_item(item_id);
867+
}
865868
}
866869
}
867870

‎compiler/rustc_hir_analysis/src/astconv/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
24262426
hir::TyKind::Tup(fields) => {
24272427
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
24282428
}
2429+
hir::TyKind::AnonAdt(item_id) => {
2430+
let did = item_id.owner_id.def_id;
2431+
let adt_def = tcx.adt_def(did);
2432+
let generics = tcx.generics_of(did);
2433+
2434+
debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
2435+
let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
2436+
tcx.mk_param_from_def(param)
2437+
});
2438+
debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
2439+
2440+
Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
2441+
}
24292442
hir::TyKind::BareFn(bf) => {
24302443
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
24312444

‎compiler/rustc_hir_analysis/src/collect.rs

+74-8
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,65 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
781781
}
782782
}
783783

784+
/*
785+
/// In a type definition, we check that unnamed field names are distinct.
786+
fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) {
787+
let mut seen_fields: FxHashMap<Ident, Option<Span>> = Default::default();
788+
fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap<Ident, Option<Span>>) {
789+
let fields = match &item.kind {
790+
hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields,
791+
_ => return,
792+
};
793+
for field in fields.fields() {
794+
if field.ident.name == kw::Underscore {
795+
if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() {
796+
let item = tcx.hir().item(item_id);
797+
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
798+
} else {
799+
let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() {
800+
Some(adt_ty) => adt_ty,
801+
None => {
802+
tcx.sess.emit_err(err);
803+
return;
804+
}
805+
};
806+
if let Some(def_id) = field_ty.did().as_local() {
807+
let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }});
808+
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
809+
}
810+
}
811+
field_ty.flags()
812+
let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt");
813+
check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields);
814+
} else {
815+
let span = field.did.as_local().map(|did| {
816+
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
817+
tcx.hir().span(hir_id)
818+
});
819+
match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() {
820+
Some(Some(prev_span)) => {
821+
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
822+
field_name: ident,
823+
span: f.span,
824+
prev_span,
825+
});
826+
}
827+
Some(None) => {
828+
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
829+
field_name: f.ident,
830+
span: f.span,
831+
prev_span,
832+
});
833+
}
834+
None =>
835+
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
836+
}
837+
}
838+
}
839+
}
840+
}
841+
*/
842+
784843
fn convert_variant(
785844
tcx: TyCtxt<'_>,
786845
variant_did: Option<LocalDefId>,
@@ -790,11 +849,17 @@ fn convert_variant(
790849
adt_kind: ty::AdtKind,
791850
parent_did: LocalDefId,
792851
) -> ty::VariantDef {
852+
let mut has_unnamed_fields = false;
793853
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
794854
let fields = def
795855
.fields()
796856
.iter()
797-
.map(|f| {
857+
.inspect(|f| {
858+
// Skip the unnamed field here, we will check it later.
859+
if f.ident.name == kw::Underscore {
860+
has_unnamed_fields = true;
861+
return;
862+
}
798863
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
799864
if let Some(prev_span) = dup_span {
800865
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
@@ -805,12 +870,11 @@ fn convert_variant(
805870
} else {
806871
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
807872
}
808-
809-
ty::FieldDef {
810-
did: f.def_id.to_def_id(),
811-
name: f.ident.name,
812-
vis: tcx.visibility(f.def_id),
813-
}
873+
})
874+
.map(|f| ty::FieldDef {
875+
did: f.def_id.to_def_id(),
876+
name: f.ident.name,
877+
vis: tcx.visibility(f.def_id),
814878
})
815879
.collect();
816880
let recovered = match def {
@@ -829,6 +893,7 @@ fn convert_variant(
829893
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
830894
|| variant_did
831895
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
896+
has_unnamed_fields,
832897
)
833898
}
834899

@@ -839,6 +904,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
839904
bug!();
840905
};
841906

907+
let is_anonymous = item.ident.name == sym::anon;
842908
let repr = tcx.repr_options_of_def(def_id.to_def_id());
843909
let (kind, variants) = match &item.kind {
844910
ItemKind::Enum(def, _) => {
@@ -889,7 +955,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
889955
}
890956
_ => bug!(),
891957
};
892-
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
958+
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
893959
}
894960

895961
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {

‎compiler/rustc_hir_pretty/src/lib.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ impl<'a> State<'a> {
323323
hir::TyKind::Infer => {
324324
self.word("_");
325325
}
326+
hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
326327
}
327328
self.end()
328329
}
@@ -743,26 +744,30 @@ impl<'a> State<'a> {
743744
}
744745
hir::VariantData::Struct(..) => {
745746
self.print_where_clause(generics);
746-
self.nbsp();
747-
self.bopen();
748-
self.hardbreak_if_not_bol();
749-
750-
for field in struct_def.fields() {
751-
self.hardbreak_if_not_bol();
752-
self.maybe_print_comment(field.span.lo());
753-
self.print_outer_attributes(self.attrs(field.hir_id));
754-
self.print_ident(field.ident);
755-
self.word_nbsp(":");
756-
self.print_type(field.ty);
757-
self.word(",");
758-
}
759-
760-
self.bclose(span)
747+
self.print_variant_struct(span, struct_def.fields())
761748
}
762749
}
763750
}
764751

765-
fn print_variant(&mut self, v: &hir::Variant<'_>) {
752+
fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
753+
self.nbsp();
754+
self.bopen();
755+
self.hardbreak_if_not_bol();
756+
757+
for field in fields {
758+
self.hardbreak_if_not_bol();
759+
self.maybe_print_comment(field.span.lo());
760+
self.print_outer_attributes(self.attrs(field.hir_id));
761+
self.print_ident(field.ident);
762+
self.word_nbsp(":");
763+
self.print_type(field.ty);
764+
self.word(",");
765+
}
766+
767+
self.bclose(span)
768+
}
769+
770+
pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
766771
self.head("");
767772
let generics = hir::Generics::empty();
768773
self.print_struct(&v.data, generics, v.ident.name, v.span, false);

0 commit comments

Comments
 (0)
Please sign in to comment.