Skip to content

Commit 3dce559

Browse files
committed
Lowering field access for anonymous adts
1 parent 128ea96 commit 3dce559

File tree

17 files changed

+388
-68
lines changed

17 files changed

+388
-68
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -1369,33 +1369,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13691369
// // ^_____________________|
13701370
// }
13711371
// ```
1372-
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1373-
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
1374-
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
1375-
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
1376-
_ => unreachable!(),
1377-
};
1378-
let def_id = self.create_def(
1379-
self.current_hir_id_owner.def_id,
1380-
*def_node_id,
1381-
kw::Empty,
1382-
def_kind,
1383-
t.span,
1384-
);
1372+
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
1373+
// Here its `def_id` is created in `build_reduced_graph`.
1374+
let def_id = self.local_def_id(*node_id);
13851375
debug!(?def_id);
13861376
let owner_id = hir::OwnerId { def_id };
1387-
self.with_hir_id_owner(*def_node_id, |this| {
1377+
self.with_hir_id_owner(*node_id, |this| {
13881378
let fields = this.arena.alloc_from_iter(
13891379
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
13901380
);
13911381
let span = t.span;
1392-
let variant_data = hir::VariantData::Struct(fields, false);
1382+
let variant_data = hir::VariantData::Struct { fields, recovered: false };
13931383
// FIXME: capture the generics from the outer adt.
13941384
let generics = hir::Generics::empty();
1385+
let kind = match t.kind {
1386+
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1387+
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
1388+
_ => unreachable!(),
1389+
};
13951390
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
13961391
ident: Ident::new(kw::Empty, span),
13971392
owner_id,
1398-
kind: item_kind(variant_data, generics),
1393+
kind,
13991394
span: this.lower_span(span),
14001395
vis_span: this.lower_span(span.shrink_to_lo()),
14011396
}))

compiler/rustc_hir_analysis/src/collect.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
3030
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
3131
use rustc_span::symbol::{kw, sym, Ident, Symbol};
3232
use rustc_span::Span;
33+
use rustc_target::abi::FieldIdx;
3334
use rustc_target::spec::abi;
3435
use rustc_trait_selection::infer::InferCtxtExt;
3536
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
@@ -81,6 +82,7 @@ pub fn provide(providers: &mut Providers) {
8182
coroutine_kind,
8283
collect_mod_item_types,
8384
is_type_alias_impl_trait,
85+
find_field,
8486
..*providers
8587
};
8688
}
@@ -867,15 +869,27 @@ fn check_field_uniqueness(
867869
// Abort due to errors (there must be an error if an unnamed field
868870
// has any type kind other than an anonymous adt or a named adt)
869871
_ => {
870-
debug_assert!(tcx.sess.has_errors().is_some());
871-
tcx.sess.abort_if_errors()
872+
debug_assert!(tcx.dcx().has_errors().is_some());
873+
tcx.dcx().abort_if_errors()
872874
}
873875
}
874876
return;
875877
}
876878
check(field.ident, field.span.into());
877879
}
878880

881+
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
882+
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
883+
if field.is_unnamed() {
884+
let field_ty = tcx.type_of(field.did).instantiate_identity();
885+
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
886+
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
887+
} else {
888+
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
889+
}
890+
})
891+
}
892+
879893
fn convert_variant(
880894
tcx: TyCtxt<'_>,
881895
variant_did: Option<LocalDefId>,
@@ -900,14 +914,14 @@ fn convert_variant(
900914
let ident = ident.normalize_to_macros_2_0();
901915
match (field_decl, seen_fields.get(&ident).copied()) {
902916
(NotNested(span), Some(NotNested(prev_span))) => {
903-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested {
917+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
904918
field_name,
905919
span,
906920
prev_span,
907921
});
908922
}
909923
(NotNested(span), Some(Nested(prev))) => {
910-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested {
924+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
911925
field_name,
912926
span,
913927
prev_span: prev.span,
@@ -918,15 +932,15 @@ fn convert_variant(
918932
Nested(NestedSpan { span, nested_field_span }),
919933
Some(NotNested(prev_span)),
920934
) => {
921-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested {
935+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
922936
field_name,
923937
span,
924938
nested_field_span,
925939
prev_span,
926940
});
927941
}
928942
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
929-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested {
943+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
930944
field_name,
931945
span,
932946
nested_field_span,

compiler/rustc_hir_typeck/src/expr.rs

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

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

2369-
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
2370-
return field_ty;
2376+
self.tcx.check_stability(
2377+
field.did,
2378+
Some(expr.hir_id),
2379+
expr.span,
2380+
None,
2381+
);
2382+
return field_ty;
2383+
}
2384+
private_candidate = Some((adjustments, base_def.did()));
2385+
break;
23712386
}
2372-
private_candidate = Some((adjustments, base_def.did()));
2387+
last_ty = Some(field_ty);
2388+
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
23732389
}
23742390
}
23752391
ty::Tuple(tys) => {
@@ -2380,7 +2396,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23802396
self.apply_adjustments(base, adjustments);
23812397
self.register_predicates(autoderef.into_obligations());
23822398

2383-
self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
2399+
self.write_field_index(
2400+
expr.hir_id,
2401+
FieldIdx::from_usize(index),
2402+
Vec::new(),
2403+
);
23842404
return field_ty;
23852405
}
23862406
}

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
@@ -229,6 +229,7 @@ trivial! {
229229
Option<rustc_span::def_id::DefId>,
230230
Option<rustc_span::def_id::LocalDefId>,
231231
Option<rustc_span::Span>,
232+
Option<rustc_target::abi::FieldIdx>,
232233
Option<rustc_target::spec::PanicStrategy>,
233234
Option<usize>,
234235
Result<(), rustc_errors::ErrorGuaranteed>,

compiler/rustc_middle/src/query/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,10 @@ rustc_queries! {
22002200
desc { "whether the item should be made inlinable across crates" }
22012201
separate_provide_extern
22022202
}
2203+
2204+
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
2205+
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
2206+
}
22032207
}
22042208

22052209
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
@@ -730,11 +730,21 @@ impl<'tcx> Cx<'tcx> {
730730
});
731731
ExprKind::Loop { body }
732732
}
733-
hir::ExprKind::Field(source, ..) => ExprKind::Field {
734-
lhs: self.mirror_expr(source),
735-
variant_index: FIRST_VARIANT,
736-
name: self.typeck_results.field_index(expr.hir_id),
737-
},
733+
hir::ExprKind::Field(source, ..) => {
734+
let mut kind = ExprKind::Field {
735+
lhs: self.mirror_expr(source),
736+
variant_index: FIRST_VARIANT,
737+
name: self.typeck_results.field_index(expr.hir_id),
738+
};
739+
let nested_field_tys_and_indices =
740+
self.typeck_results.nested_field_tys_and_indices(expr.hir_id);
741+
for &(ty, idx) in nested_field_tys_and_indices {
742+
let expr = Expr { temp_lifetime, ty, span: source.span, kind };
743+
let lhs = self.thir.exprs.push(expr);
744+
kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx };
745+
}
746+
kind
747+
}
738748
hir::ExprKind::Cast(source, cast_ty) => {
739749
// Check for a user-given type annotation on this `cast`
740750
let user_provided_types = self.typeck_results.user_provided_types();

0 commit comments

Comments
 (0)