Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lower struct patterns and struct expressions with unnamed fields #121553

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 2 additions & 23 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
Expand Down Expand Up @@ -84,7 +83,6 @@ pub fn provide(providers: &mut Providers) {
coroutine_for_closure,
collect_mod_item_types,
is_type_alias_impl_trait,
find_field,
..*providers
};
}
Expand Down Expand Up @@ -790,18 +788,6 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
}
}

fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
if field.is_unnamed() {
let field_ty = tcx.type_of(field.did).instantiate_identity();
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
} else {
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
}
})
}

#[derive(Clone, Copy)]
struct NestedSpan {
span: Span,
Expand Down Expand Up @@ -899,15 +885,8 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
for field in adt_def.all_fields() {
if field.is_unnamed() {
// Here we don't care about the generic parameters, so `instantiate_identity` is enough.
match self.tcx.type_of(field.did).instantiate_identity().kind() {
ty::Adt(adt_def, _) => {
self.check_field_in_nested_adt(*adt_def, unnamed_field_span);
}
ty_kind => span_bug!(
self.tcx.def_span(field.did),
"Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
),
}
let adt_def = field.nested_adt_def(self.tcx);
self.check_field_in_nested_adt(adt_def, unnamed_field_span);
} else {
self.check_field_decl(
field.ident(self.tcx),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_typeck/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ hir_typeck_trivial_cast = trivial {$numeric ->
}: `{$expr_ty}` as `{$cast_ty}`
.help = cast can be replaced by coercion; this might require a temporary variable

hir_typeck_union_pat_absent = there are no fields from this union
.label = union defined here

hir_typeck_union_pat_conflict = there are multiple fields from this union

hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns

hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,29 @@ pub struct ConstSelectMustBeFn<'a> {
pub ty: Ty<'a>,
}

#[derive(Subdiagnostic)]
#[note(hir_typeck_union_pat_absent)]
pub struct UnionPatAbsent {
#[primary_span]
pub span: MultiSpan,
}

#[derive(Subdiagnostic)]
#[note(hir_typeck_union_pat_conflict)]
pub struct UnionPatConflict {
#[primary_span]
pub span: MultiSpan,
}

#[derive(Diagnostic)]
#[diag(hir_typeck_union_pat_multiple_fields)]
pub struct UnionPatMultipleFields {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub conflict_set: Vec<UnionPatConflict>,
#[subdiagnostic]
pub absent_set: Vec<UnionPatAbsent>,
}

#[derive(Diagnostic)]
Expand Down
44 changes: 13 additions & 31 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2363,39 +2363,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
let mut adt_def = *base_def;
let mut last_ty = None;
let mut nested_fields = Vec::new();
let mut index = None;
while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
let &mut first_idx = index.get_or_insert(idx);
let field = &adt_def.non_enum_variant().fields[idx];
let field_ty = self.field_ty(expr.span, field, args);
if let Some(ty) = last_ty {
nested_fields.push((ty, idx));
}
if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, first_idx, nested_fields);
let adjustments = self.adjust_steps(&autoderef);
if field.vis.is_accessible_from(def_scope, self.tcx) {
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());
if let Some((first_idx, nested_fields, field, field_ty)) =
self.lookup_ident(base_def.non_enum_variant(), ident, args, expr.span)
{
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, first_idx, nested_fields);
let adjustments = self.adjust_steps(&autoderef);
if field.vis.is_accessible_from(def_scope, self.tcx) {
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());

self.tcx.check_stability(
field.did,
Some(expr.hir_id),
expr.span,
None,
);
return field_ty;
}
private_candidate = Some((adjustments, base_def.did()));
break;
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
return field_ty;
}
last_ty = Some(field_ty);
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
private_candidate = Some((adjustments, base_def.did()));
}
}
ty::Tuple(tys) => {
Expand Down
33 changes: 33 additions & 0 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

pub fn lookup_ident(
&self,
variant: &'tcx ty::VariantDef,
ident: Ident,
args: GenericArgsRef<'tcx>,
span: Span,
) -> Option<(
// The outer-most field index
FieldIdx,
// The nested fields, see `TypeckResults::nested_fields`
Vec<(Ty<'tcx>, FieldIdx)>,
// The inner-most field def
&'tcx ty::FieldDef,
// The inner-most field type
Ty<'tcx>,
)> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a type.

let path = self
.typeck_results
.borrow_mut()
.lookup_field(self.tcx, variant, ident)
.map(|(idx, field)| (idx, field, self.field_ty(span, field, args)))
.collect::<Vec<_>>();
match &path[..] {
[] => None,
&[(idx, field, ty)] => Some((idx, Vec::new(), field, ty)),
&[(idx, ..), .., (_, field, ty)] => {
let nested_fields =
path.array_windows().map(|&[(.., ty), (idx, ..)]| (ty, idx)).collect();
Some((idx, nested_fields, field, ty))
}
}
}

#[instrument(level = "debug", skip(self))]
pub(in super::super) fn write_resolution(
&self,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_typeck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![feature(try_blocks)]
#![feature(never_type)]
#![feature(box_patterns)]
#![feature(array_windows)]
#![cfg_attr(bootstrap, feature(min_specialization))]
#![feature(control_flow_enum)]

Expand Down
Loading
Loading