Push down the decision to skip fields

This commit is contained in:
Nadrieril 2024-02-06 02:35:59 +01:00
parent ef324565d0
commit be01e28dce

View file

@ -165,13 +165,14 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
&self, &self,
ty: RevealedTy<'tcx>, ty: RevealedTy<'tcx>,
variant: &'tcx VariantDef, variant: &'tcx VariantDef,
) -> impl Iterator<Item = (FieldIdx, RevealedTy<'tcx>)> + Captures<'p> + Captures<'_> { ) -> impl Iterator<Item = (FieldIdx, RevealedTy<'tcx>, bool)> + Captures<'p> + Captures<'_>
{
let cx = self; let cx = self;
let ty::Adt(adt, args) = ty.kind() else { bug!() }; let ty::Adt(adt, args) = ty.kind() else { bug!() };
// Whether we must not match the fields of this variant exhaustively. // Whether we must avoid matching the fields of this variant exhaustively.
let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local(); let is_non_exhaustive = variant.is_field_list_non_exhaustive() && !adt.did().is_local();
variant.fields.iter().enumerate().filter_map(move |(i, field)| { variant.fields.iter().enumerate().map(move |(i, field)| {
let ty = field.ty(cx.tcx, args); let ty = field.ty(cx.tcx, args);
// `field.ty()` doesn't normalize after instantiating. // `field.ty()` doesn't normalize after instantiating.
let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
@ -180,12 +181,9 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
|| cx.tcx.features().min_exhaustive_patterns) || cx.tcx.features().min_exhaustive_patterns)
&& cx.is_uninhabited(ty); && cx.is_uninhabited(ty);
if is_uninhabited && (!is_visible || is_non_exhaustive) { let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
None
} else {
let ty = cx.reveal_opaque_ty(ty); let ty = cx.reveal_opaque_ty(ty);
Some((FieldIdx::new(i), ty)) (FieldIdx::new(i), ty, skip)
}
}) })
} }
@ -229,7 +227,10 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
} else { } else {
let variant = let variant =
&adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt)); &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
let tys = cx.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty); let tys = cx
.list_variant_nonhidden_fields(ty, variant)
.filter(|(_, _, skip)| !skip)
.map(|(_, ty, _)| ty);
cx.dropless_arena.alloc_from_iter(tys) cx.dropless_arena.alloc_from_iter(tys)
} }
} }
@ -276,7 +277,9 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
} else { } else {
let variant = let variant =
&adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt)); &adt.variant(RustcMatchCheckCtxt::variant_index_for_adt(&ctor, *adt));
self.list_variant_nonhidden_fields(ty, variant).count() self.list_variant_nonhidden_fields(ty, variant)
.filter(|(_, _, skip)| !skip)
.count()
} }
} }
_ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"),
@ -523,12 +526,14 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
// For each field in the variant, we store the relevant index into `self.fields` if any. // For each field in the variant, we store the relevant index into `self.fields` if any.
let mut field_id_to_id: Vec<Option<usize>> = let mut field_id_to_id: Vec<Option<usize>> =
(0..variant.fields.len()).map(|_| None).collect(); (0..variant.fields.len()).map(|_| None).collect();
let tys = cx.list_variant_nonhidden_fields(ty, variant).enumerate().map( let tys = cx
|(i, (field, ty))| { .list_variant_nonhidden_fields(ty, variant)
.filter(|(_, _, skip)| !skip)
.enumerate()
.map(|(i, (field, ty, _))| {
field_id_to_id[field.index()] = Some(i); field_id_to_id[field.index()] = Some(i);
ty ty
}, });
);
fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect(); fields = tys.map(|ty| DeconstructedPat::wildcard(ty)).collect();
for pat in subpatterns { for pat in subpatterns {
if let Some(i) = field_id_to_id[pat.field.index()] { if let Some(i) = field_id_to_id[pat.field.index()] {
@ -778,8 +783,9 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> {
let variant = &adt_def.variant(variant_index); let variant = &adt_def.variant(variant_index);
let subpatterns = cx let subpatterns = cx
.list_variant_nonhidden_fields(*pat.ty(), variant) .list_variant_nonhidden_fields(*pat.ty(), variant)
.filter(|(_, _, skip)| !skip)
.zip(subpatterns) .zip(subpatterns)
.map(|((field, _ty), pattern)| FieldPat { field, pattern }) .map(|((field, _ty, _), pattern)| FieldPat { field, pattern })
.collect(); .collect();
if adt_def.is_enum() { if adt_def.is_enum() {