Skip to content

Commit 729188e

Browse files
committed
Lowering field access for anonymous adts
1 parent 1dc00ff commit 729188e

File tree

18 files changed

+390
-70
lines changed

18 files changed

+390
-70
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -1351,33 +1351,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13511351
// // ^_____________________|
13521352
// }
13531353
// ```
1354-
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1355-
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
1356-
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
1357-
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
1358-
_ => unreachable!(),
1359-
};
1360-
let def_id = self.create_def(
1361-
self.current_hir_id_owner.def_id,
1362-
*def_node_id,
1363-
kw::Empty,
1364-
def_kind,
1365-
t.span,
1366-
);
1354+
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
1355+
// Here its `def_id` is created in `build_reduced_graph`.
1356+
let def_id = self.local_def_id(*node_id);
13671357
debug!(?def_id);
13681358
let owner_id = hir::OwnerId { def_id };
1369-
self.with_hir_id_owner(*def_node_id, |this| {
1359+
self.with_hir_id_owner(*node_id, |this| {
13701360
let fields = this.arena.alloc_from_iter(
13711361
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
13721362
);
13731363
let span = t.span;
1374-
let variant_data = hir::VariantData::Struct(fields, false);
1364+
let variant_data = hir::VariantData::Struct { fields, recovered: false };
13751365
// FIXME: capture the generics from the outer adt.
13761366
let generics = hir::Generics::empty();
1367+
let kind = match t.kind {
1368+
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1369+
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
1370+
_ => unreachable!(),
1371+
};
13771372
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
13781373
ident: Ident::new(kw::Empty, span),
13791374
owner_id,
1380-
kind: item_kind(variant_data, generics),
1375+
kind,
13811376
span: this.lower_span(span),
13821377
vis_span: this.lower_span(span.shrink_to_lo()),
13831378
}))

compiler/rustc_hir_analysis/src/collect.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
3131
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
3232
use rustc_span::symbol::{kw, sym, Ident, Symbol};
3333
use rustc_span::Span;
34+
use rustc_target::abi::FieldIdx;
3435
use rustc_target::spec::abi;
3536
use rustc_trait_selection::infer::InferCtxtExt;
3637
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
@@ -83,6 +84,7 @@ pub fn provide(providers: &mut Providers) {
8384
coroutine_kind,
8485
collect_mod_item_types,
8586
is_type_alias_impl_trait,
87+
find_field,
8688
..*providers
8789
};
8890
}
@@ -877,15 +879,27 @@ fn check_field_uniqueness(
877879
// Abort due to errors (there must be an error if an unnamed field
878880
// has any type kind other than an anonymous adt or a named adt)
879881
_ => {
880-
debug_assert!(tcx.sess.has_errors().is_some());
881-
tcx.sess.abort_if_errors()
882+
debug_assert!(tcx.dcx().has_errors().is_some());
883+
tcx.dcx().abort_if_errors()
882884
}
883885
}
884886
return;
885887
}
886888
check(field.ident, field.span.into());
887889
}
888890

891+
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
892+
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
893+
if field.is_unnamed() {
894+
let field_ty = tcx.type_of(field.did).instantiate_identity();
895+
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
896+
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
897+
} else {
898+
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
899+
}
900+
})
901+
}
902+
889903
fn convert_variant(
890904
tcx: TyCtxt<'_>,
891905
variant_did: Option<LocalDefId>,
@@ -910,14 +924,14 @@ fn convert_variant(
910924
let ident = ident.normalize_to_macros_2_0();
911925
match (field_decl, seen_fields.get(&ident).copied()) {
912926
(NotNested(span), Some(NotNested(prev_span))) => {
913-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested {
927+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
914928
field_name,
915929
span,
916930
prev_span,
917931
});
918932
}
919933
(NotNested(span), Some(Nested(prev))) => {
920-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested {
934+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
921935
field_name,
922936
span,
923937
prev_span: prev.span,
@@ -928,15 +942,15 @@ fn convert_variant(
928942
Nested(NestedSpan { span, nested_field_span }),
929943
Some(NotNested(prev_span)),
930944
) => {
931-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested {
945+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
932946
field_name,
933947
span,
934948
nested_field_span,
935949
prev_span,
936950
});
937951
}
938952
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
939-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested {
953+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
940954
field_name,
941955
span,
942956
nested_field_span,

compiler/rustc_hir_typeck/src/expr.rs

+37-17
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17101710
let ident = tcx.adjust_ident(field.ident, variant.def_id);
17111711
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
17121712
seen_fields.insert(ident, field.span);
1713-
self.write_field_index(field.hir_id, i);
1713+
// FIXME: handle nested fields
1714+
self.write_field_index(field.hir_id, i, Vec::new());
17141715

17151716
// We don't look at stability attributes on
17161717
// struct-like enums (yet...), but it's definitely not
@@ -2355,24 +2356,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23552356
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
23562357
let (ident, def_scope) =
23572358
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
2358-
let fields = &base_def.non_enum_variant().fields;
2359-
if let Some((index, field)) = fields
2360-
.iter_enumerated()
2361-
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
2362-
{
2359+
let mut adt_def = *base_def;
2360+
let mut last_ty = None;
2361+
let mut nested_fields = Vec::new();
2362+
let mut index = None;
2363+
while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
2364+
let &mut first_idx = index.get_or_insert(idx);
2365+
let field = &adt_def.non_enum_variant().fields[idx];
23632366
let field_ty = self.field_ty(expr.span, field, args);
2364-
// Save the index of all fields regardless of their visibility in case
2365-
// of error recovery.
2366-
self.write_field_index(expr.hir_id, index);
2367-
let adjustments = self.adjust_steps(&autoderef);
2368-
if field.vis.is_accessible_from(def_scope, self.tcx) {
2369-
self.apply_adjustments(base, adjustments);
2370-
self.register_predicates(autoderef.into_obligations());
2367+
if let Some(ty) = last_ty {
2368+
nested_fields.push((ty, idx));
2369+
}
2370+
if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
2371+
// Save the index of all fields regardless of their visibility in case
2372+
// of error recovery.
2373+
self.write_field_index(expr.hir_id, first_idx, nested_fields);
2374+
let adjustments = self.adjust_steps(&autoderef);
2375+
if field.vis.is_accessible_from(def_scope, self.tcx) {
2376+
self.apply_adjustments(base, adjustments);
2377+
self.register_predicates(autoderef.into_obligations());
23712378

2372-
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
2373-
return field_ty;
2379+
self.tcx.check_stability(
2380+
field.did,
2381+
Some(expr.hir_id),
2382+
expr.span,
2383+
None,
2384+
);
2385+
return field_ty;
2386+
}
2387+
private_candidate = Some((adjustments, base_def.did()));
2388+
break;
23742389
}
2375-
private_candidate = Some((adjustments, base_def.did()));
2390+
last_ty = Some(field_ty);
2391+
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
23762392
}
23772393
}
23782394
ty::Tuple(tys) => {
@@ -2383,7 +2399,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23832399
self.apply_adjustments(base, adjustments);
23842400
self.register_predicates(autoderef.into_obligations());
23852401

2386-
self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
2402+
self.write_field_index(
2403+
expr.hir_id,
2404+
FieldIdx::from_usize(index),
2405+
Vec::new(),
2406+
);
23872407
return field_ty;
23882408
}
23892409
}

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
145145
}
146146
}
147147

148-
pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) {
148+
pub fn write_field_index(
149+
&self,
150+
hir_id: hir::HirId,
151+
index: FieldIdx,
152+
nested_fields: Vec<(Ty<'tcx>, FieldIdx)>,
153+
) {
149154
self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
155+
if !nested_fields.is_empty() {
156+
self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields);
157+
}
150158
}
151159

152160
#[instrument(level = "debug", skip(self))]

compiler/rustc_hir_typeck/src/pat.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1390,7 +1390,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13901390
field_map
13911391
.get(&ident)
13921392
.map(|(i, f)| {
1393-
self.write_field_index(field.hir_id, *i);
1393+
// FIXME: handle nested fields
1394+
self.write_field_index(field.hir_id, *i, Vec::new());
13941395
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
13951396
self.field_ty(span, f, args)
13961397
})

compiler/rustc_hir_typeck/src/writeback.rs

+5
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
596596
{
597597
self.typeck_results.field_indices_mut().insert(hir_id, index);
598598
}
599+
if let Some(nested_fields) =
600+
self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id)
601+
{
602+
self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields);
603+
}
599604
}
600605

601606
#[instrument(skip(self, span), level = "debug")]

compiler/rustc_middle/src/query/erase.rs

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ trivial! {
238238
Option<rustc_span::def_id::DefId>,
239239
Option<rustc_span::def_id::LocalDefId>,
240240
Option<rustc_span::Span>,
241+
Option<rustc_target::abi::FieldIdx>,
241242
Option<rustc_target::spec::PanicStrategy>,
242243
Option<usize>,
243244
Result<(), rustc_errors::ErrorGuaranteed>,

compiler/rustc_middle/src/query/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2212,6 +2212,10 @@ rustc_queries! {
22122212
desc { "whether the item should be made inlinable across crates" }
22132213
separate_provide_extern
22142214
}
2215+
2216+
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
2217+
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
2218+
}
22152219
}
22162220

22172221
rustc_query_append! { define_callbacks! }

compiler/rustc_middle/src/ty/typeck_results.rs

+19
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ pub struct TypeckResults<'tcx> {
4444
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
4545
field_indices: ItemLocalMap<FieldIdx>,
4646

47+
/// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded
48+
/// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type
49+
/// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of
50+
/// `_(2).field`.
51+
nested_fields: ItemLocalMap<Vec<(Ty<'tcx>, FieldIdx)>>,
52+
4753
/// Stores the types for various nodes in the AST. Note that this table
4854
/// is not guaranteed to be populated outside inference. See
4955
/// typeck::check::fn_ctxt for details.
@@ -214,6 +220,7 @@ impl<'tcx> TypeckResults<'tcx> {
214220
hir_owner,
215221
type_dependent_defs: Default::default(),
216222
field_indices: Default::default(),
223+
nested_fields: Default::default(),
217224
user_provided_types: Default::default(),
218225
user_provided_sigs: Default::default(),
219226
node_types: Default::default(),
@@ -285,6 +292,18 @@ impl<'tcx> TypeckResults<'tcx> {
285292
self.field_indices().get(id).cloned()
286293
}
287294

295+
pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
296+
LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields }
297+
}
298+
299+
pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
300+
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields }
301+
}
302+
303+
pub fn nested_field_tys_and_indices(&self, id: hir::HirId) -> &[(Ty<'tcx>, FieldIdx)] {
304+
self.nested_fields().get(id).map_or(&[], Vec::as_slice)
305+
}
306+
288307
pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
289308
LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
290309
}

compiler/rustc_mir_build/src/thir/cx/expr.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -731,11 +731,21 @@ impl<'tcx> Cx<'tcx> {
731731
});
732732
ExprKind::Loop { body }
733733
}
734-
hir::ExprKind::Field(source, ..) => ExprKind::Field {
735-
lhs: self.mirror_expr(source),
736-
variant_index: FIRST_VARIANT,
737-
name: self.typeck_results.field_index(expr.hir_id),
738-
},
734+
hir::ExprKind::Field(source, ..) => {
735+
let mut kind = ExprKind::Field {
736+
lhs: self.mirror_expr(source),
737+
variant_index: FIRST_VARIANT,
738+
name: self.typeck_results.field_index(expr.hir_id),
739+
};
740+
let nested_field_tys_and_indices =
741+
self.typeck_results.nested_field_tys_and_indices(expr.hir_id);
742+
for &(ty, idx) in nested_field_tys_and_indices {
743+
let expr = Expr { temp_lifetime, ty, span: source.span, kind };
744+
let lhs = self.thir.exprs.push(expr);
745+
kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx };
746+
}
747+
kind
748+
}
739749
hir::ExprKind::Cast(source, cast_ty) => {
740750
// Check for a user-given type annotation on this `cast`
741751
let user_provided_types = self.typeck_results.user_provided_types();

0 commit comments

Comments
 (0)