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 | 104 |
1 files changed, 37 insertions, 67 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 dd82a0f45c..56fd12e1f2 100644 --- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -6,7 +6,7 @@ use std::fmt; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use intern::sym; use rustc_pattern_analysis::{ - Captures, IndexVec, PatCx, PrivateUninhabitedField, + IndexVec, PatCx, PrivateUninhabitedField, constructor::{Constructor, ConstructorSet, VariantVisibility}, usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness}, }; @@ -21,7 +21,7 @@ use crate::{ inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from}, }; -use super::{FieldPat, Pat, PatKind, is_box}; +use super::{FieldPat, Pat, PatKind}; use Constructor::*; @@ -50,7 +50,7 @@ impl EnumVariantContiguousIndex { } fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId { - db.enum_variants(eid).variants[self.0].0 + eid.enum_variants(db).variants[self.0].0 } } @@ -138,15 +138,15 @@ impl<'db> MatchCheckCtx<'db> { } // This lists the fields of a variant along with their types. - fn list_variant_fields<'a>( - &'a self, - ty: &'a Ty, + fn list_variant_fields( + &self, + ty: &Ty, variant: VariantId, - ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> { + ) -> impl Iterator<Item = (LocalFieldId, Ty)> { let (_, substs) = ty.as_adt().unwrap(); let field_tys = self.db.field_types(variant); - let fields_len = variant.variant_data(self.db).fields().len() as u32; + let fields_len = variant.fields(self.db).fields().len() as u32; (0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).map(move |fid| { let ty = field_tys[fid].clone().substitute(Interner, substs); @@ -170,8 +170,6 @@ impl<'db> MatchCheckCtx<'db> { } PatKind::Deref { subpattern } => { ctor = match pat.ty.kind(Interner) { - // This is a box pattern. - TyKind::Adt(adt, _) if is_box(self.db, adt.0) => Struct, TyKind::Ref(..) => Ref, _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); @@ -194,23 +192,6 @@ impl<'db> MatchCheckCtx<'db> { ctor = Struct; arity = substs.len(Interner); } - TyKind::Adt(adt, _) if is_box(self.db, adt.0) => { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - // FIXME(Nadrieril): A `Box` can in theory be matched either with `Box(_, - // _)` or a box pattern. As a hack to avoid an ICE with the former, we - // ignore other fields than the first one. This will trigger an error later - // anyway. - // See https://github.com/rust-lang/rust/issues/82772 , - // explanation: https://github.com/rust-lang/rust/pull/82789#issuecomment-796921977 - // The problem is that we can't know from the type whether we'll match - // normally or through box-patterns. We'll have to figure out a proper - // solution when we introduce generalized deref patterns. Also need to - // prevent mixing of those two options. - fields.retain(|ipat| ipat.idx == 0); - ctor = Struct; - arity = 1; - } &TyKind::Adt(AdtId(adt), _) => { ctor = match pat.kind.as_ref() { PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => { @@ -229,7 +210,7 @@ impl<'db> MatchCheckCtx<'db> { } }; let variant = Self::variant_id_for_adt(self.db, &ctor, adt).unwrap(); - arity = variant.variant_data(self.db).fields().len(); + arity = variant.fields(self.db).fields().len(); } _ => { never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty); @@ -277,12 +258,6 @@ impl<'db> MatchCheckCtx<'db> { }) .collect(), }, - TyKind::Adt(adt, _) if is_box(self.db, adt.0) => { - // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside - // of `std`). So this branch is only reachable when the feature is enabled and - // the pattern is a box pattern. - PatKind::Deref { subpattern: subpatterns.next().unwrap() } - } TyKind::Adt(adt, substs) => { let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap(); let subpatterns = self @@ -343,14 +318,8 @@ impl PatCx for MatchCheckCtx<'_> { Struct | Variant(_) | UnionField => match *ty.kind(Interner) { TyKind::Tuple(arity, ..) => arity, TyKind::Adt(AdtId(adt), ..) => { - if is_box(self.db, adt) { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - 1 - } else { - let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - variant.variant_data(self.db).fields().len() - } + let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); + variant.fields(self.db).fields().len() } _ => { never!("Unexpected type for `Single` constructor: {:?}", ty); @@ -383,29 +352,22 @@ impl PatCx for MatchCheckCtx<'_> { tys.cloned().map(|ty| (ty, PrivateUninhabitedField(false))).collect() } TyKind::Ref(.., rty) => single(rty.clone()), - &TyKind::Adt(AdtId(adt), ref substs) => { - if is_box(self.db, adt) { - // The only legal patterns of type `Box` (outside `std`) are `_` and box - // patterns. If we're here we can assume this is a box pattern. - let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone(); - single(subst_ty) - } else { - let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - - let visibilities = LazyCell::new(|| 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, self.module) - }; - let is_uninhabited = self.is_uninhabited(&ty); - let private_uninhabited = is_uninhabited && !is_visible(); - (ty, PrivateUninhabitedField(private_uninhabited)) - }) - .collect() - } + &TyKind::Adt(AdtId(adt), ..) => { + let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); + + let visibilities = LazyCell::new(|| 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, self.module) + }; + let is_uninhabited = self.is_uninhabited(&ty); + let private_uninhabited = is_uninhabited && !is_visible(); + (ty, PrivateUninhabitedField(private_uninhabited)) + }) + .collect() } ty_kind => { never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind); @@ -458,14 +420,14 @@ impl PatCx for MatchCheckCtx<'_> { TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), TyKind::Array(..) | TyKind::Slice(..) => unhandled(), &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => { - let enum_data = cx.db.enum_variants(enum_id); + let enum_data = enum_id.enum_variants(cx.db); let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt); if enum_data.variants.is_empty() && !is_declared_nonexhaustive { ConstructorSet::NoConstructors } else { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let is_uninhabited = is_enum_variant_uninhabited_from( cx.db, variant, @@ -527,6 +489,14 @@ impl PatCx for MatchCheckCtx<'_> { fn complexity_exceeded(&self) -> Result<(), Self::Error> { Err(()) } + + fn report_mixed_deref_pat_ctors( + &self, + _deref_pat: &DeconstructedPat<'_>, + _normal_pat: &DeconstructedPat<'_>, + ) { + // FIXME(deref_patterns): This could report an error comparable to the one in rustc. + } } impl fmt::Debug for MatchCheckCtx<'_> { |