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 Aug 30, 2023
1 parent 868706d commit d9347ee
Show file tree
Hide file tree
Showing 28 changed files with 197 additions and 65 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ 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
26 changes: 14 additions & 12 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,18 +1293,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Err => {
hir::TyKind::Err(self.tcx.sess.delay_span_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(fields) => {
let hir_id = self.next_id();
hir::TyKind::AnonStruct(
self.arena.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
hir_id,
)
}
TyKind::AnonUnion(fields) => {
let hir_id = self.next_id();
hir::TyKind::AnonUnion(
self.arena.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
hir_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
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
enum_type_di_node,
std::iter::once((
variant_index,
Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
Cow::from(enum_adt_def.variant(variant_index).name_ref().as_str()),
)),
);

Expand Down Expand Up @@ -399,7 +399,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>(
cx,
enum_type_di_node,
variant_indices.clone().map(|variant_index| {
let variant_name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
let variant_name = Cow::from(enum_adt_def.variant(variant_index).name_ref().as_str());
(variant_index, variant_name)
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ fn build_c_style_enum_di_node<'ll, 'tcx>(
&compute_debuginfo_type_name(cx.tcx, enum_type_and_layout.ty, false),
tag_base_type(cx, enum_type_and_layout),
enum_adt_def.discriminants(cx.tcx).map(|(variant_index, discr)| {
let name = Cow::from(enum_adt_def.variant(variant_index).name.as_str());
let name = Cow::from(enum_adt_def.variant(variant_index).name_ref().as_str());
(name, discr.val)
}),
containing_scope,
Expand Down Expand Up @@ -263,7 +263,7 @@ fn build_enum_variant_struct_type_di_node<'ll, 'tcx>(
enum_type_and_layout.ty,
variant_index,
),
variant_def.name.as_str(),
variant_def.name().as_str(),
// NOTE: We use size and align of enum_type, not from variant_layout:
size_and_align_of(enum_type_and_layout),
Some(enum_type_di_node),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
.variant_range()
.map(|variant_index| VariantMemberInfo {
variant_index,
variant_name: Cow::from(enum_adt_def.variant(variant_index).name.as_str()),
variant_name: Cow::from(enum_adt_def.variant(variant_index).name_ref().as_str()),
variant_struct_type_di_node: super::build_enum_variant_struct_type_di_node(
cx,
enum_type_and_layout,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn uncached_llvm_type<'a, 'tcx>(
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants().is_empty() {
write!(&mut name, "::{}", def.variant(index).name).unwrap();
write!(&mut name, "::{}", def.variant(index).name()).unwrap();
}
}
if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
new_op: &OpTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx> {
let name = match old_op.layout.ty.kind() {
ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name),
ty::Adt(adt, _) => PathElem::Variant(adt.variant(variant_id).name()),
// Generators also have variants
ty::Generator(..) => PathElem::GeneratorState(variant_id),
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2713,6 +2713,10 @@ pub enum TyKind<'hir> {
Never,
/// A tuple (`(A, B, C, D, ...)`).
Tup(&'hir [Ty<'hir>]),
/// An anonymous struct type i.e. `struct { foo: Type }`
AnonStruct(&'hir [FieldDef<'hir>], HirId),
/// An anonymous union type i.e. `union { bar: Type }`
AnonUnion(&'hir [FieldDef<'hir>], HirId),
/// 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::AnonStruct(fields, _hir_id) | TyKind::AnonUnion(fields, _hir_id) => {
walk_list!(visitor, visit_field_def, fields);
}
}
}

Expand Down
58 changes: 57 additions & 1 deletion compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&adt_def
.variants()
.iter()
.map(|variant| variant.name)
.map(|variant| variant.name())
.collect::<Vec<Symbol>>(),
assoc_ident.name,
None,
Expand Down Expand Up @@ -2524,6 +2524,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.ty_infer(None, ast_ty.span)
}
hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
&hir::TyKind::AnonStruct(fields, hir_id) | &hir::TyKind::AnonUnion(fields, hir_id) => {
let repr = tcx.repr_options_of_def(hir_id.owner.to_def_id());
if !repr.c() {
// tcx.sess.emit_err(todo!());
}
let adt_kind = match ast_ty.kind {
hir::TyKind::AnonStruct(..) => ty::AdtKind::Struct,
_ => ty::AdtKind::Union,
};
let field_def = tcx.hir().expect_field(tcx.hir().parent_id(hir_id));
let did = field_def.def_id;
let variants = std::iter::once(convert_variant(
tcx,
did,
fields,
adt_kind,
))
.collect();
let adt_def = tcx.mk_adt_def(did.to_def_id(), adt_kind, variants, repr);
Ty::new_adt(tcx, adt_def, tcx.mk_args(&[]))
}
};

self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span);
Expand Down Expand Up @@ -2813,3 +2834,38 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Some(r)
}
}

fn convert_variant(
tcx: TyCtxt<'_>,
did: LocalDefId,
fields: &[hir::FieldDef<'_>],
adt_kind: ty::AdtKind,
) -> ty::VariantDef {
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
let fields = fields
.iter()
.map(|f| {
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(crate::errors::FieldAlreadyDeclared {
field_name: f.ident,
span: f.span,
prev_span,
});
} 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),
}
})
.collect();
ty::VariantDef::new_anon(
did.to_def_id(),
fields,
adt_kind,
)
}
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1323,8 +1323,8 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
{
let explicit_variant = adt.variant(explicit_idx);
let ve_ident = var.name;
let ex_ident = explicit_variant.name;
let ve_ident = var.name();
let ex_ident = explicit_variant.name();
let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };

err.span_label(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
}
}

fn convert_variant(
pub(crate) fn convert_variant(
tcx: TyCtxt<'_>,
variant_did: Option<LocalDefId>,
ident: Ident,
Expand Down
42 changes: 27 additions & 15 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,14 @@ impl<'a> State<'a> {
hir::TyKind::Infer => {
self.word("_");
}
hir::TyKind::AnonStruct(fields, _hir_id) => {
self.word("struct");
self.print_variant_struct(ty.span, fields);
}
hir::TyKind::AnonUnion(fields, _hir_id) => {
self.word("union");
self.print_variant_struct(ty.span, fields);
}
}
self.end()
}
Expand Down Expand Up @@ -788,25 +796,29 @@ 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_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();
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1740,7 +1740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&cause,
target_ty,
fru_ty,
FieldMisMatch(variant.name, ident.name),
FieldMisMatch(variant.name(), ident.name),
)
.emit();
}
Expand Down Expand Up @@ -2060,7 +2060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
"{} `{}::{}` has no field named `{}`",
kind_name,
actual,
variant.name,
variant.name(),
field.ident
),
_ => struct_span_err!(
Expand All @@ -2085,7 +2085,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(
"`{adt}::{variant}` defined here",
adt = ty,
variant = variant.name,
variant = variant.name(),
),
);
err.span_label(field.ident.span, "field does not exist");
Expand All @@ -2094,12 +2094,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
variant = variant.name,
variant = variant.name(),
),
format!(
"{adt}::{variant}(/* fields */)",
adt = ty,
variant = variant.name,
variant = variant.name(),
),
Applicability::HasPlaceholders,
);
Expand Down Expand Up @@ -2133,7 +2133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if adt.is_enum() {
err.span_label(
field.ident.span,
format!("`{}::{}` does not have this field", ty, variant.name),
format!("`{}::{}` does not have this field", ty, variant.name()),
);
} else {
err.span_label(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1174,7 +1174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() {
let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = edit_distance::find_best_match_for_name(
&adt_def.variants().iter().map(|s| s.name).collect::<Vec<_>>(),
&adt_def.variants().iter().map(|s| s.name()).collect::<Vec<_>>(),
item_name.name,
None,
) {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,13 @@ impl<'hir> Map<'hir> {
}
}

pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> {
match self.find(id) {
Some(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(id) {
Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2737,7 +2737,7 @@ impl UserTypeProjection {
field_index: FieldIdx,
) -> Self {
self.projs.push(ProjectionElem::Downcast(
Some(adt_def.variant(variant_index).name),
Some(adt_def.variant(variant_index).name()),
variant_index,
));
self.projs.push(ProjectionElem::Field(field_index, ()));
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,9 +815,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did)
|| tcx.get_diagnostic_item(sym::Result) == Some(adt_did)
{
variant.name.to_string()
variant.name().to_string()
} else {
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name())
};
Some((variant, name))
}),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1673,7 +1673,7 @@ impl<'tcx> TyCtxt<'tcx> {
) -> Place<'tcx> {
self.mk_place_elem(
place,
PlaceElem::Downcast(Some(adt_def.variant(variant_index).name), variant_index),
PlaceElem::Downcast(Some(adt_def.variant(variant_index).name()), variant_index),
)
}

Expand Down
Loading

0 comments on commit d9347ee

Please sign in to comment.