Skip to content

Commit 0c0df4e

Browse files
committed
Lowering field access for anonymous adts
1 parent 36d7e7f commit 0c0df4e

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
@@ -1299,33 +1299,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12991299
// // ^_____________________|
13001300
// }
13011301
// ```
1302-
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1303-
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
1304-
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
1305-
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
1306-
_ => unreachable!(),
1307-
};
1308-
let def_id = self.create_def(
1309-
self.current_hir_id_owner.def_id,
1310-
*def_node_id,
1311-
kw::Empty,
1312-
def_kind,
1313-
t.span,
1314-
);
1302+
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
1303+
// Here its `def_id` is created in `build_reduced_graph`.
1304+
let def_id = self.local_def_id(*node_id);
13151305
debug!(?def_id);
13161306
let owner_id = hir::OwnerId { def_id };
1317-
self.with_hir_id_owner(*def_node_id, |this| {
1307+
self.with_hir_id_owner(*node_id, |this| {
13181308
let fields = this.arena.alloc_from_iter(
13191309
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
13201310
);
13211311
let span = t.span;
1322-
let variant_data = hir::VariantData::Struct(fields, false);
1312+
let variant_data = hir::VariantData::Struct { fields, recovered: false };
13231313
// FIXME: capture the generics from the outer adt.
13241314
let generics = hir::Generics::empty();
1315+
let kind = match t.kind {
1316+
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1317+
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
1318+
_ => unreachable!(),
1319+
};
13251320
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
13261321
ident: Ident::new(kw::Empty, span),
13271322
owner_id,
1328-
kind: item_kind(variant_data, generics),
1323+
kind,
13291324
span: this.lower_span(span),
13301325
vis_span: this.lower_span(span.shrink_to_lo()),
13311326
}))

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;
@@ -84,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
8485
coroutine_for_closure,
8586
collect_mod_item_types,
8687
is_type_alias_impl_trait,
88+
find_field,
8789
..*providers
8890
};
8991
}
@@ -875,15 +877,27 @@ fn check_field_uniqueness(
875877
// Abort due to errors (there must be an error if an unnamed field
876878
// has any type kind other than an anonymous adt or a named adt)
877879
_ => {
878-
debug_assert!(tcx.sess.has_errors().is_some());
879-
tcx.sess.abort_if_errors()
880+
debug_assert!(tcx.dcx().has_errors().is_some());
881+
tcx.dcx().abort_if_errors()
880882
}
881883
}
882884
return;
883885
}
884886
check(field.ident, field.span.into());
885887
}
886888

889+
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
890+
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
891+
if field.is_unnamed() {
892+
let field_ty = tcx.type_of(field.did).instantiate_identity();
893+
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
894+
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
895+
} else {
896+
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
897+
}
898+
})
899+
}
900+
887901
fn convert_variant(
888902
tcx: TyCtxt<'_>,
889903
variant_did: Option<LocalDefId>,
@@ -908,14 +922,14 @@ fn convert_variant(
908922
let ident = ident.normalize_to_macros_2_0();
909923
match (field_decl, seen_fields.get(&ident).copied()) {
910924
(NotNested(span), Some(NotNested(prev_span))) => {
911-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested {
925+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
912926
field_name,
913927
span,
914928
prev_span,
915929
});
916930
}
917931
(NotNested(span), Some(Nested(prev))) => {
918-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested {
932+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
919933
field_name,
920934
span,
921935
prev_span: prev.span,
@@ -926,15 +940,15 @@ fn convert_variant(
926940
Nested(NestedSpan { span, nested_field_span }),
927941
Some(NotNested(prev_span)),
928942
) => {
929-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested {
943+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
930944
field_name,
931945
span,
932946
nested_field_span,
933947
prev_span,
934948
});
935949
}
936950
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
937-
tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested {
951+
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
938952
field_name,
939953
span,
940954
nested_field_span,

compiler/rustc_hir_typeck/src/expr.rs

+37-17
Original file line numberDiff line numberDiff line change
@@ -1721,7 +1721,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17211721
let ident = tcx.adjust_ident(field.ident, variant.def_id);
17221722
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
17231723
seen_fields.insert(ident, field.span);
1724-
self.write_field_index(field.hir_id, i);
1724+
// FIXME: handle nested fields
1725+
self.write_field_index(field.hir_id, i, Vec::new());
17251726

17261727
// We don't look at stability attributes on
17271728
// struct-like enums (yet...), but it's definitely not
@@ -2367,24 +2368,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23672368
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
23682369
let (ident, def_scope) =
23692370
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
2370-
let fields = &base_def.non_enum_variant().fields;
2371-
if let Some((index, field)) = fields
2372-
.iter_enumerated()
2373-
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
2374-
{
2371+
let mut adt_def = *base_def;
2372+
let mut last_ty = None;
2373+
let mut nested_fields = Vec::new();
2374+
let mut index = None;
2375+
while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
2376+
let &mut first_idx = index.get_or_insert(idx);
2377+
let field = &adt_def.non_enum_variant().fields[idx];
23752378
let field_ty = self.field_ty(expr.span, field, args);
2376-
// Save the index of all fields regardless of their visibility in case
2377-
// of error recovery.
2378-
self.write_field_index(expr.hir_id, index);
2379-
let adjustments = self.adjust_steps(&autoderef);
2380-
if field.vis.is_accessible_from(def_scope, self.tcx) {
2381-
self.apply_adjustments(base, adjustments);
2382-
self.register_predicates(autoderef.into_obligations());
2379+
if let Some(ty) = last_ty {
2380+
nested_fields.push((ty, idx));
2381+
}
2382+
if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
2383+
// Save the index of all fields regardless of their visibility in case
2384+
// of error recovery.
2385+
self.write_field_index(expr.hir_id, first_idx, nested_fields);
2386+
let adjustments = self.adjust_steps(&autoderef);
2387+
if field.vis.is_accessible_from(def_scope, self.tcx) {
2388+
self.apply_adjustments(base, adjustments);
2389+
self.register_predicates(autoderef.into_obligations());
23832390

2384-
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
2385-
return field_ty;
2391+
self.tcx.check_stability(
2392+
field.did,
2393+
Some(expr.hir_id),
2394+
expr.span,
2395+
None,
2396+
);
2397+
return field_ty;
2398+
}
2399+
private_candidate = Some((adjustments, base_def.did()));
2400+
break;
23862401
}
2387-
private_candidate = Some((adjustments, base_def.did()));
2402+
last_ty = Some(field_ty);
2403+
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
23882404
}
23892405
}
23902406
ty::Tuple(tys) => {
@@ -2395,7 +2411,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23952411
self.apply_adjustments(base, adjustments);
23962412
self.register_predicates(autoderef.into_obligations());
23972413

2398-
self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
2414+
self.write_field_index(
2415+
expr.hir_id,
2416+
FieldIdx::from_usize(index),
2417+
Vec::new(),
2418+
);
23992419
return field_ty;
24002420
}
24012421
}

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
@@ -1389,7 +1389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13891389
field_map
13901390
.get(&ident)
13911391
.map(|(i, f)| {
1392-
self.write_field_index(field.hir_id, *i);
1392+
// FIXME: handle nested fields
1393+
self.write_field_index(field.hir_id, *i, Vec::new());
13931394
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
13941395
self.field_ty(span, f, args)
13951396
})

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
@@ -2217,6 +2217,10 @@ rustc_queries! {
22172217
desc { "whether the item should be made inlinable across crates" }
22182218
separate_provide_extern
22192219
}
2220+
2221+
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
2222+
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
2223+
}
22202224
}
22212225

22222226
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
@@ -734,11 +734,21 @@ impl<'tcx> Cx<'tcx> {
734734
});
735735
ExprKind::Loop { body }
736736
}
737-
hir::ExprKind::Field(source, ..) => ExprKind::Field {
738-
lhs: self.mirror_expr(source),
739-
variant_index: FIRST_VARIANT,
740-
name: self.typeck_results.field_index(expr.hir_id),
741-
},
737+
hir::ExprKind::Field(source, ..) => {
738+
let mut kind = ExprKind::Field {
739+
lhs: self.mirror_expr(source),
740+
variant_index: FIRST_VARIANT,
741+
name: self.typeck_results.field_index(expr.hir_id),
742+
};
743+
let nested_field_tys_and_indices =
744+
self.typeck_results.nested_field_tys_and_indices(expr.hir_id);
745+
for &(ty, idx) in nested_field_tys_and_indices {
746+
let expr = Expr { temp_lifetime, ty, span: source.span, kind };
747+
let lhs = self.thir.exprs.push(expr);
748+
kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx };
749+
}
750+
kind
751+
}
742752
hir::ExprKind::Cast(source, cast_ty) => {
743753
// Check for a user-given type annotation on this `cast`
744754
let user_provided_types = self.typeck_results.user_provided_types();

0 commit comments

Comments
 (0)