Skip to content

Commit aaee42b

Browse files
committed
Lowering field access for anonymous adts
1 parent 4d173eb commit aaee42b

File tree

18 files changed

+390
-70
lines changed

18 files changed

+390
-70
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,33 +1353,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13531353
// // ^_____________________|
13541354
// }
13551355
// ```
1356-
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1357-
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
1358-
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
1359-
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
1360-
_ => unreachable!(),
1361-
};
1362-
let def_id = self.create_def(
1363-
self.current_hir_id_owner.def_id,
1364-
*def_node_id,
1365-
kw::Empty,
1366-
def_kind,
1367-
t.span,
1368-
);
1356+
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
1357+
// Here its `def_id` is created in `build_reduced_graph`.
1358+
let def_id = self.local_def_id(*node_id);
13691359
debug!(?def_id);
13701360
let owner_id = hir::OwnerId { def_id };
1371-
self.with_hir_id_owner(*def_node_id, |this| {
1361+
self.with_hir_id_owner(*node_id, |this| {
13721362
let fields = this.arena.alloc_from_iter(
13731363
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
13741364
);
13751365
let span = t.span;
1376-
let variant_data = hir::VariantData::Struct(fields, false);
1366+
let variant_data = hir::VariantData::Struct { fields, recovered: false };
13771367
// FIXME: capture the generics from the outer adt.
13781368
let generics = hir::Generics::empty();
1369+
let kind = match t.kind {
1370+
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1371+
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
1372+
_ => unreachable!(),
1373+
};
13791374
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
13801375
ident: Ident::new(kw::Empty, span),
13811376
owner_id,
1382-
kind: item_kind(variant_data, generics),
1377+
kind,
13831378
span: this.lower_span(span),
13841379
vis_span: this.lower_span(span.shrink_to_lo()),
13851380
}))

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 20 additions & 6 deletions
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

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,7 +1705,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17051705
let ident = tcx.adjust_ident(field.ident, variant.def_id);
17061706
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
17071707
seen_fields.insert(ident, field.span);
1708-
self.write_field_index(field.hir_id, i);
1708+
// FIXME: handle nested fields
1709+
self.write_field_index(field.hir_id, i, Vec::new());
17091710

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

2366-
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
2367-
return field_ty;
2373+
self.tcx.check_stability(
2374+
field.did,
2375+
Some(expr.hir_id),
2376+
expr.span,
2377+
None,
2378+
);
2379+
return field_ty;
2380+
}
2381+
private_candidate = Some((adjustments, base_def.did()));
2382+
break;
23682383
}
2369-
private_candidate = Some((adjustments, base_def.did()));
2384+
last_ty = Some(field_ty);
2385+
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
23702386
}
23712387
}
23722388
ty::Tuple(tys) => {
@@ -2377,7 +2393,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23772393
self.apply_adjustments(base, adjustments);
23782394
self.register_predicates(autoderef.into_obligations());
23792395

2380-
self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
2396+
self.write_field_index(
2397+
expr.hir_id,
2398+
FieldIdx::from_usize(index),
2399+
Vec::new(),
2400+
);
23812401
return field_ty;
23822402
}
23832403
}

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 9 additions & 1 deletion
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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1388,7 +1388,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13881388
field_map
13891389
.get(&ident)
13901390
.map(|(i, f)| {
1391-
self.write_field_index(field.hir_id, *i);
1391+
// FIXME: handle nested fields
1392+
self.write_field_index(field.hir_id, *i, Vec::new());
13921393
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
13931394
self.field_ty(span, f, args)
13941395
})

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 5 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2196,6 +2196,10 @@ rustc_queries! {
21962196
desc { "whether the item should be made inlinable across crates" }
21972197
separate_provide_extern
21982198
}
2199+
2200+
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
2201+
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
2202+
}
21992203
}
22002204

22012205
rustc_query_append! { define_callbacks! }

compiler/rustc_middle/src/ty/typeck_results.rs

Lines changed: 19 additions & 0 deletions
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

Lines changed: 15 additions & 5 deletions
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)