Skip to content

Commit

Permalink
Lowering anonymous structs or unions to HIR (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
frank-king committed Dec 14, 2023
1 parent c3def26 commit a8b76fc
Show file tree
Hide file tree
Showing 36 changed files with 278 additions and 173 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2108,9 +2108,9 @@ pub enum TyKind {
/// A tuple (`(A, B, C, D,...)`).
Tup(ThinVec<P<Ty>>),
/// An anonymous struct type i.e. `struct { foo: Type }`
AnonStruct(ThinVec<FieldDef>),
AnonStruct(NodeId, ThinVec<FieldDef>),
/// An anonymous union type i.e. `union { bar: Type }`
AnonUnion(ThinVec<FieldDef>),
AnonUnion(NodeId, ThinVec<FieldDef>),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
///
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
vis.visit_id(id);
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
TyKind::Never | TyKind::CVarArgs => {}
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
walk_list!(visitor, visit_field_def, fields)
}
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
pub(super) fn lower_field_def(
&mut self,
(index, f): (usize, &FieldDef),
) -> hir::FieldDef<'hir> {
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
let t = self.lower_path_ty(
&f.ty,
Expand Down
48 changes: 36 additions & 12 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,18 +1326,42 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Err => {
hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered"))
}
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
),
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
),
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
let def_kind = match t.kind {
TyKind::AnonStruct(..) => DefKind::Struct,
TyKind::AnonUnion(..) => DefKind::Union,
_ => unreachable!(),
};
let def_id = self.create_def(
self.current_hir_id_owner.def_id,
*def_node_id,
sym::anon,
def_kind,
t.span,
);
debug!(?def_id);
let owner_id = hir::OwnerId { def_id };
self.with_hir_id_owner(*def_node_id, |this| {
let fields = this.arena.alloc_from_iter(
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
);
let span = t.span;
let variant_data = hir::VariantData::Struct(fields, false);
let generics = hir::Generics::empty();
let kind = match &t.kind {
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
_ => hir::ItemKind::Union(variant_data, generics),
};
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
ident: Ident::with_dummy_span(sym::anon),
owner_id,
kind,
span: this.lower_span(span),
vis_span: this.lower_span(span.shrink_to_lo()),
}))
});
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
}
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl<'a> AstValidator<'a> {
}
}
}
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
walk_list!(self, visit_field_def, fields)
}
_ => visit::walk_ty(self, t),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -987,11 +987,11 @@ impl<'a> State<'a> {
}
self.pclose();
}
ast::TyKind::AnonStruct(fields) => {
ast::TyKind::AnonStruct(_, fields) => {
self.head("struct");
self.print_record_struct_body(fields, ty.span);
}
ast::TyKind::AnonUnion(fields) => {
ast::TyKind::AnonUnion(_, fields) => {
self.head("union");
self.print_record_struct_body(fields, ty.span);
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_macros::HashStable_Generic;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::sym;
use rustc_span::Symbol;

use std::array::IntoIter;
Expand Down Expand Up @@ -225,6 +226,7 @@ impl DefKind {

pub fn def_path_data(self, name: Symbol) -> DefPathData {
match self {
DefKind::Struct | DefKind::Union if name == sym::anon => DefPathData::AnonAdt,
DefKind::Mod
| DefKind::Struct
| DefKind::Union
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ pub enum DefPathData {
/// An existential `impl Trait` type node.
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
OpaqueTy,
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
AnonAdt,
}

impl Definitions {
Expand Down Expand Up @@ -404,8 +406,9 @@ impl DefPathData {
match *self {
TypeNs(name) if name == kw::Empty => None,
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),

Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
| OpaqueTy => None,
| OpaqueTy | AnonAdt => None,
}
}

Expand All @@ -426,6 +429,7 @@ impl DefPathData {
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
AnonAdt => DefPathDataName::Anon { namespace: sym::anon },
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2543,6 +2543,8 @@ pub enum TyKind<'hir> {
Never,
/// A tuple (`(A, B, C, D, ...)`).
Tup(&'hir [Ty<'hir>]),
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
AnonAdt(ItemId),
/// A path to a type definition (`module::module::...::Type`), or an
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
///
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
}
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::Err(_) => {}
TyKind::AnonAdt(item_id) => {
visitor.visit_nested_item(item_id);
}
}
}

Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2426,6 +2426,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
hir::TyKind::Tup(fields) => {
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
}
hir::TyKind::AnonAdt(item_id) => {
let did = item_id.owner_id.def_id;
let adt_def = tcx.adt_def(did);
let generics = tcx.generics_of(did);

debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
tcx.mk_param_from_def(param)
});
debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);

Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
}
hir::TyKind::BareFn(bf) => {
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);

Expand Down
82 changes: 74 additions & 8 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,65 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
}
}

/*
/// In a type definition, we check that unnamed field names are distinct.
fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) {
let mut seen_fields: FxHashMap<Ident, Option<Span>> = Default::default();
fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap<Ident, Option<Span>>) {
let fields = match &item.kind {
hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields,
_ => return,
};
for field in fields.fields() {
if field.ident.name == kw::Underscore {
if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() {
let item = tcx.hir().item(item_id);
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
} else {
let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() {
Some(adt_ty) => adt_ty,
None => {
tcx.sess.emit_err(err);
return;
}
};
if let Some(def_id) = field_ty.did().as_local() {
let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }});
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
}
}
field_ty.flags()
let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt");
check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields);
} else {
let span = field.did.as_local().map(|did| {
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
tcx.hir().span(hir_id)
});
match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() {
Some(Some(prev_span)) => {
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
field_name: ident,
span: f.span,
prev_span,
});
}
Some(None) => {
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
field_name: f.ident,
span: f.span,
prev_span,
});
}
None =>
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}
}
}
}
}
*/

fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option<LocalDefId>,
Expand All @@ -790,11 +849,17 @@ fn convert_variant(
adt_kind: ty::AdtKind,
parent_did: LocalDefId,
) -> ty::VariantDef {
let mut has_unnamed_fields = false;
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
let fields = def
.fields()
.iter()
.map(|f| {
.inspect(|f| {
// Skip the unnamed field here, we will check it later.
if f.ident.name == kw::Underscore {
has_unnamed_fields = true;
return;
}
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
if let Some(prev_span) = dup_span {
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
Expand All @@ -805,12 +870,11 @@ fn convert_variant(
} else {
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
}

ty::FieldDef {
did: f.def_id.to_def_id(),
name: f.ident.name,
vis: tcx.visibility(f.def_id),
}
})
.map(|f| ty::FieldDef {
did: f.def_id.to_def_id(),
name: f.ident.name,
vis: tcx.visibility(f.def_id),
})
.collect();
let recovered = match def {
Expand All @@ -829,6 +893,7 @@ fn convert_variant(
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|| variant_did
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
has_unnamed_fields,
)
}

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

let is_anonymous = item.ident.name == sym::anon;
let repr = tcx.repr_options_of_def(def_id.to_def_id());
let (kind, variants) = match &item.kind {
ItemKind::Enum(def, _) => {
Expand Down Expand Up @@ -889,7 +955,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
}
_ => bug!(),
};
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
}

fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
Expand Down
37 changes: 21 additions & 16 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ impl<'a> State<'a> {
hir::TyKind::Infer => {
self.word("_");
}
hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
}
self.end()
}
Expand Down Expand Up @@ -743,26 +744,30 @@ impl<'a> State<'a> {
}
hir::VariantData::Struct(..) => {
self.print_where_clause(generics);
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();

for field in struct_def.fields() {
self.hardbreak_if_not_bol();
self.maybe_print_comment(field.span.lo());
self.print_outer_attributes(self.attrs(field.hir_id));
self.print_ident(field.ident);
self.word_nbsp(":");
self.print_type(field.ty);
self.word(",");
}

self.bclose(span)
self.print_variant_struct(span, struct_def.fields())
}
}
}

fn print_variant(&mut self, v: &hir::Variant<'_>) {
fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();

for field in fields {
self.hardbreak_if_not_bol();
self.maybe_print_comment(field.span.lo());
self.print_outer_attributes(self.attrs(field.hir_id));
self.print_ident(field.ident);
self.word_nbsp(":");
self.print_type(field.ty);
self.word(",");
}

self.bclose(span)
}

pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
self.head("");
let generics = hir::Generics::empty();
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
Expand Down
Loading

0 comments on commit a8b76fc

Please sign in to comment.