Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs')
| -rw-r--r-- | crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs | 106 |
1 files changed, 53 insertions, 53 deletions
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index e98a946a87..ca05842879 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; use rustc_pattern_analysis::{ constructor::{Constructor, ConstructorSet, VariantVisibility}, index::IdxContainer, - Captures, TypeCx, + Captures, PrivateUninhabitedField, TypeCx, }; use smallvec::{smallvec, SmallVec}; use stdx::never; @@ -88,39 +88,21 @@ impl<'p> MatchCheckCtx<'p> { } } - // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide - // uninhabited fields in order not to reveal the uninhabitedness of the whole variant. - // This lists the fields we keep along with their types. - fn list_variant_nonhidden_fields<'a>( + // This lists the fields of a variant along with their types. + fn list_variant_fields<'a>( &'a self, ty: &'a Ty, variant: VariantId, ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'p> { - let cx = self; - let (adt, substs) = ty.as_adt().unwrap(); - - let adt_is_local = variant.module(cx.db.upcast()).krate() == cx.module.krate(); - - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - cx.db.attrs(variant.into()).by_key("non_exhaustive").exists() && !adt_is_local; + let (_, substs) = ty.as_adt().unwrap(); - let visibility = cx.db.field_visibilities(variant); - let field_ty = cx.db.field_types(variant); - let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32; + let field_tys = self.db.field_types(variant); + let fields_len = variant.variant_data(self.db.upcast()).fields().len() as u32; - (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| { - let ty = field_ty[fid].clone().substitute(Interner, substs); - let ty = normalize(cx.db, cx.db.trait_environment_for_body(cx.body), ty); - let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) - || visibility[fid].is_visible_from(cx.db.upcast(), cx.module); - let is_uninhabited = cx.is_uninhabited(&ty); - - if is_uninhabited && (!is_visible || is_non_exhaustive) { - None - } else { - Some((fid, ty)) - } + (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| { + let ty = field_tys[fid].clone().substitute(Interner, substs); + let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty); + (fid, ty) }) } @@ -199,23 +181,16 @@ impl<'p> MatchCheckCtx<'p> { } }; let variant = Self::variant_id_for_adt(&ctor, adt.0).unwrap(); - let fields_len = variant.variant_data(self.db.upcast()).fields().len(); - // 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>> = vec![None; fields_len]; - let tys = self - .list_variant_nonhidden_fields(&pat.ty, variant) - .enumerate() - .map(|(i, (fid, ty))| { - let field_idx: u32 = fid.into_raw().into(); - field_id_to_id[field_idx as usize] = Some(i); - ty - }); - let mut wilds: Vec<_> = tys.map(DeconstructedPat::wildcard).collect(); + // Fill a vec with wildcards, then place the fields we have at the right + // index. + let mut wilds: Vec<_> = self + .list_variant_fields(&pat.ty, variant) + .map(|(_, ty)| ty) + .map(DeconstructedPat::wildcard) + .collect(); for pat in subpatterns { - let field_idx: u32 = pat.field.into_raw().into(); - if let Some(i) = field_id_to_id[field_idx as usize] { - wilds[i] = self.lower_pat(&pat.pattern); - } + let field_id: u32 = pat.field.into_raw().into(); + wilds[field_id as usize] = self.lower_pat(&pat.pattern); } fields = wilds; } @@ -263,7 +238,7 @@ impl<'p> MatchCheckCtx<'p> { TyKind::Adt(adt, substs) => { let variant = Self::variant_id_for_adt(pat.ctor(), adt.0).unwrap(); let subpatterns = self - .list_variant_nonhidden_fields(pat.ty(), variant) + .list_variant_fields(pat.ty(), variant) .zip(subpatterns) .map(|((field, _ty), pattern)| FieldPat { field, pattern }) .collect(); @@ -286,7 +261,7 @@ impl<'p> MatchCheckCtx<'p> { Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), &Str(void) => match void {}, - Wildcard | NonExhaustive | Hidden => PatKind::Wild, + Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => { never!("can't convert to pattern: {:?}", pat.ctor()); PatKind::Wild @@ -326,7 +301,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { 1 } else { let variant = Self::variant_id_for_adt(ctor, adt).unwrap(); - self.list_variant_nonhidden_fields(ty, variant).count() + variant.variant_data(self.db.upcast()).fields().len() } } _ => { @@ -337,7 +312,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { Ref => 1, Slice(..) => unimplemented!(), Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | Wildcard => 0, + | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, Or => { never!("The `Or` constructor doesn't have a fixed arity"); 0 @@ -349,13 +324,13 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { &'a self, ctor: &'a rustc_pattern_analysis::constructor::Constructor<Self>, ty: &'a Self::Ty, - ) -> impl ExactSizeIterator<Item = Self::Ty> + Captures<'a> { - let single = |ty| smallvec![ty]; + ) -> impl ExactSizeIterator<Item = (Self::Ty, PrivateUninhabitedField)> + Captures<'a> { + let single = |ty| smallvec![(ty, PrivateUninhabitedField(false))]; let tys: SmallVec<[_; 2]> = match ctor { Struct | Variant(_) | UnionField => match ty.kind(Interner) { TyKind::Tuple(_, substs) => { let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner)); - tys.cloned().collect() + tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect() } TyKind::Ref(.., rty) => single(rty.clone()), &TyKind::Adt(AdtId(adt), ref substs) => { @@ -366,7 +341,27 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { single(subst_ty) } else { let variant = Self::variant_id_for_adt(ctor, adt).unwrap(); - self.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty).collect() + let (adt, _) = ty.as_adt().unwrap(); + + let adt_is_local = + variant.module(self.db.upcast()).krate() == self.module.krate(); + // Whether we must not match the fields of this variant exhaustively. + let is_non_exhaustive = + self.db.attrs(variant.into()).by_key("non_exhaustive").exists() + && !adt_is_local; + let visibilities = self.db.field_visibilities(variant); + + self.list_variant_fields(ty, variant) + .map(move |(fid, ty)| { + let is_visible = matches!(adt, hir_def::AdtId::EnumId(..)) + || visibilities[fid] + .is_visible_from(self.db.upcast(), self.module); + let is_uninhabited = self.is_uninhabited(&ty); + let private_uninhabited = + is_uninhabited && (!is_visible || is_non_exhaustive); + (ty, PrivateUninhabitedField(private_uninhabited)) + }) + .collect() } } ty_kind => { @@ -383,7 +378,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | NonExhaustive | Hidden | Missing | Wildcard => smallvec![], + | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => smallvec![], Or => { never!("called `Fields::wildcards` on an `Or` ctor"); smallvec![] @@ -478,6 +473,11 @@ impl<'p> TypeCx for MatchCheckCtx<'p> { fn bug(&self, fmt: fmt::Arguments<'_>) { debug!("{}", fmt) } + + fn complexity_exceeded(&self) -> Result<(), Self::Error> { + // FIXME(Nadrieril): make use of the complexity counter. + Err(()) + } } impl<'p> fmt::Debug for MatchCheckCtx<'p> { |