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.rs207
1 files changed, 114 insertions, 93 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 eb20d3c51f..fb942e336e 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -1,24 +1,27 @@
//! Interface with `rustc_pattern_analysis`.
-use std::cell::LazyCell;
-use std::fmt;
+use std::{cell::LazyCell, fmt};
-use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
+use hir_def::{EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
use intern::sym;
use rustc_pattern_analysis::{
IndexVec, PatCx, PrivateUninhabitedField,
constructor::{Constructor, ConstructorSet, VariantVisibility},
usefulness::{PlaceValidity, UsefulnessReport, compute_match_usefulness},
};
+use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike};
use smallvec::{SmallVec, smallvec};
use stdx::never;
use triomphe::Arc;
use crate::{
- AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind,
+ TraitEnvironment,
db::HirDatabase,
- infer::normalize,
inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
+ next_solver::{
+ Ty, TyKind,
+ infer::{InferCtxt, traits::ObligationCause},
+ },
};
use super::{FieldPat, Pat, PatKind};
@@ -26,10 +29,12 @@ use super::{FieldPat, Pat, PatKind};
use Constructor::*;
// Re-export r-a-specific versions of all these types.
-pub(crate) type DeconstructedPat<'db> =
- rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'db>>;
-pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>;
-pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'db>>;
+pub(crate) type DeconstructedPat<'a, 'db> =
+ rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'a, 'db>>;
+pub(crate) type MatchArm<'a, 'b, 'db> =
+ rustc_pattern_analysis::MatchArm<'b, MatchCheckCtx<'a, 'db>>;
+pub(crate) type WitnessPat<'a, 'db> =
+ rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'a, 'db>>;
/// [Constructor] uses this in unimplemented variants.
/// It allows porting match expressions from upstream algorithm without losing semantics.
@@ -65,37 +70,37 @@ impl rustc_pattern_analysis::Idx for EnumVariantContiguousIndex {
}
#[derive(Clone)]
-pub(crate) struct MatchCheckCtx<'db> {
+pub(crate) struct MatchCheckCtx<'a, 'db> {
module: ModuleId,
- body: DefWithBodyId,
pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool,
env: Arc<TraitEnvironment<'db>>,
+ infcx: &'a InferCtxt<'db>,
}
-impl<'db> MatchCheckCtx<'db> {
+impl<'a, 'db> MatchCheckCtx<'a, 'db> {
pub(crate) fn new(
module: ModuleId,
- body: DefWithBodyId,
- db: &'db dyn HirDatabase,
+ infcx: &'a InferCtxt<'db>,
env: Arc<TraitEnvironment<'db>>,
) -> Self {
+ let db = infcx.interner.db;
let def_map = module.crate_def_map(db);
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
- Self { module, body, db, exhaustive_patterns, env }
+ Self { module, db, exhaustive_patterns, env, infcx }
}
- pub(crate) fn compute_match_usefulness(
+ pub(crate) fn compute_match_usefulness<'b>(
&self,
- arms: &[MatchArm<'db>],
- scrut_ty: Ty,
+ arms: &[MatchArm<'a, 'b, 'db>],
+ scrut_ty: Ty<'db>,
known_valid_scrutinee: Option<bool>,
- ) -> Result<UsefulnessReport<'db, Self>, ()> {
- if scrut_ty.contains_unknown() {
+ ) -> Result<UsefulnessReport<'b, Self>, ()> {
+ if scrut_ty.references_non_lt_error() {
return Err(());
}
for arm in arms {
- if arm.pat.ty().contains_unknown() {
+ if arm.pat.ty().references_non_lt_error() {
return Err(());
}
}
@@ -106,8 +111,8 @@ impl<'db> MatchCheckCtx<'db> {
compute_match_usefulness(self, arms, scrut_ty, place_validity, complexity_limit)
}
- fn is_uninhabited(&self, ty: &Ty) -> bool {
- is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone())
+ fn is_uninhabited(&self, ty: Ty<'db>) -> bool {
+ is_ty_uninhabited_from(self.infcx, ty, self.module, self.env.clone())
}
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
@@ -140,23 +145,27 @@ impl<'db> MatchCheckCtx<'db> {
// This lists the fields of a variant along with their types.
fn list_variant_fields(
&self,
- ty: &Ty,
+ ty: Ty<'db>,
variant: VariantId,
- ) -> impl Iterator<Item = (LocalFieldId, Ty)> {
+ ) -> impl Iterator<Item = (LocalFieldId, Ty<'db>)> {
let (_, substs) = ty.as_adt().unwrap();
let field_tys = self.db.field_types(variant);
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);
- let ty = normalize(self.db, self.db.trait_environment_for_body(self.body), ty);
+ let ty = field_tys[fid].instantiate(self.infcx.interner, substs);
+ let ty = self
+ .infcx
+ .at(&ObligationCause::dummy(), self.env.env)
+ .deeply_normalize(ty)
+ .unwrap_or(ty);
(fid, ty)
})
}
- pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> {
- let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)];
+ pub(crate) fn lower_pat(&self, pat: &Pat<'db>) -> DeconstructedPat<'a, 'db> {
+ let singleton = |pat: DeconstructedPat<'a, 'db>| vec![pat.at_index(0)];
let ctor;
let mut fields: Vec<_>;
let arity;
@@ -169,7 +178,7 @@ impl<'db> MatchCheckCtx<'db> {
arity = 0;
}
PatKind::Deref { subpattern } => {
- ctor = match pat.ty.kind(Interner) {
+ ctor = match pat.ty.kind() {
TyKind::Ref(..) => Ref,
_ => {
never!("pattern has unexpected type: pat: {:?}, ty: {:?}", pat, &pat.ty);
@@ -187,12 +196,13 @@ impl<'db> MatchCheckCtx<'db> {
self.lower_pat(&pat.pattern).at_index(idx as usize)
})
.collect();
- match pat.ty.kind(Interner) {
- TyKind::Tuple(_, substs) => {
+ match pat.ty.kind() {
+ TyKind::Tuple(substs) => {
ctor = Struct;
- arity = substs.len(Interner);
+ arity = substs.len();
}
- &TyKind::Adt(AdtId(adt), _) => {
+ TyKind::Adt(adt_def, _) => {
+ let adt = adt_def.def_id().0;
ctor = match pat.kind.as_ref() {
PatKind::Leaf { .. } if matches!(adt, hir_def::AdtId::UnionId(_)) => {
UnionField
@@ -240,15 +250,15 @@ impl<'db> MatchCheckCtx<'db> {
arity = pats.len();
}
}
- DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ())
+ DeconstructedPat::new(ctor, fields, arity, pat.ty, ())
}
- pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat {
+ pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'a, 'db>) -> Pat<'db> {
let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p));
let kind = match pat.ctor() {
&Bool(value) => PatKind::LiteralBool { value },
IntRange(_) => unimplemented!(),
- Struct | Variant(_) | UnionField => match pat.ty().kind(Interner) {
+ Struct | Variant(_) | UnionField => match pat.ty().kind() {
TyKind::Tuple(..) => PatKind::Leaf {
subpatterns: subpatterns
.zip(0u32..)
@@ -259,15 +269,16 @@ impl<'db> MatchCheckCtx<'db> {
.collect(),
},
TyKind::Adt(adt, substs) => {
- let variant = Self::variant_id_for_adt(self.db, pat.ctor(), adt.0).unwrap();
+ let variant =
+ Self::variant_id_for_adt(self.db, pat.ctor(), adt.def_id().0).unwrap();
let subpatterns = self
- .list_variant_fields(pat.ty(), variant)
+ .list_variant_fields(*pat.ty(), variant)
.zip(subpatterns)
.map(|((field, _ty), pattern)| FieldPat { field, pattern })
.collect();
if let VariantId::EnumVariantId(enum_variant) = variant {
- PatKind::Variant { substs: substs.clone(), enum_variant, subpatterns }
+ PatKind::Variant { substs, enum_variant, subpatterns }
} else {
PatKind::Leaf { subpatterns }
}
@@ -293,13 +304,13 @@ impl<'db> MatchCheckCtx<'db> {
PatKind::Wild
}
};
- Pat { ty: pat.ty().clone(), kind: Box::new(kind) }
+ Pat { ty: *pat.ty(), kind: Box::new(kind) }
}
}
-impl PatCx for MatchCheckCtx<'_> {
+impl<'a, 'db> PatCx for MatchCheckCtx<'a, 'db> {
type Error = ();
- type Ty = Ty;
+ type Ty = Ty<'db>;
type VariantIdx = EnumVariantContiguousIndex;
type StrLit = Void;
type ArmData = ();
@@ -315,10 +326,11 @@ impl PatCx for MatchCheckCtx<'_> {
ty: &Self::Ty,
) -> usize {
match ctor {
- Struct | Variant(_) | UnionField => match *ty.kind(Interner) {
- TyKind::Tuple(arity, ..) => arity,
- TyKind::Adt(AdtId(adt), ..) => {
- let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
+ Struct | Variant(_) | UnionField => match ty.kind() {
+ TyKind::Tuple(tys) => tys.len(),
+ TyKind::Adt(adt_def, ..) => {
+ let variant =
+ Self::variant_id_for_adt(self.db, ctor, adt_def.def_id().0).unwrap();
variant.fields(self.db).fields().len()
}
_ => {
@@ -346,24 +358,24 @@ impl PatCx for MatchCheckCtx<'_> {
) -> impl ExactSizeIterator<Item = (Self::Ty, PrivateUninhabitedField)> {
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().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
+ Struct | Variant(_) | UnionField => match ty.kind() {
+ TyKind::Tuple(substs) => {
+ substs.iter().map(|ty| (ty, PrivateUninhabitedField(false))).collect()
}
- TyKind::Ref(.., rty) => single(rty.clone()),
- &TyKind::Adt(AdtId(adt), ..) => {
+ TyKind::Ref(_, rty, _) => single(rty),
+ TyKind::Adt(adt_def, ..) => {
+ let adt = adt_def.def_id().0;
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)
+ 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 is_uninhabited = self.is_uninhabited(ty);
let private_uninhabited = is_uninhabited && !is_visible();
(ty, PrivateUninhabitedField(private_uninhabited))
})
@@ -371,14 +383,14 @@ impl PatCx for MatchCheckCtx<'_> {
}
ty_kind => {
never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
- single(ty.clone())
+ single(*ty)
}
},
- Ref => match ty.kind(Interner) {
- TyKind::Ref(.., rty) => single(rty.clone()),
+ Ref => match ty.kind() {
+ TyKind::Ref(_, rty, _) => single(rty),
ty_kind => {
never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
- single(ty.clone())
+ single(*ty)
}
},
Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
@@ -414,42 +426,51 @@ impl PatCx for MatchCheckCtx<'_> {
// returned list of constructors.
// Invariant: this is empty if and only if the type is uninhabited (as determined by
// `cx.is_uninhabited()`).
- Ok(match ty.kind(Interner) {
- TyKind::Scalar(Scalar::Bool) => ConstructorSet::Bool,
- TyKind::Scalar(Scalar::Char) => unhandled(),
- TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
+ Ok(match ty.kind() {
+ TyKind::Bool => ConstructorSet::Bool,
+ TyKind::Char => unhandled(),
+ TyKind::Int(..) | TyKind::Uint(..) => unhandled(),
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
- &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
- 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() {
- let is_uninhabited = is_enum_variant_uninhabited_from(
- cx.db,
- variant,
- subst,
- cx.module,
- self.env.clone(),
- );
- let visibility = if is_uninhabited {
- VariantVisibility::Empty
+ TyKind::Adt(adt_def, subst) => {
+ let adt = adt_def.def_id().0;
+ match adt {
+ hir_def::AdtId::EnumId(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 {
- VariantVisibility::Visible
- };
- variants.push(visibility);
- }
+ let mut variants = IndexVec::with_capacity(enum_data.variants.len());
+ for &(variant, _, _) in enum_data.variants.iter() {
+ let is_uninhabited = is_enum_variant_uninhabited_from(
+ cx.infcx,
+ variant,
+ subst,
+ cx.module,
+ self.env.clone(),
+ );
+ let visibility = if is_uninhabited {
+ VariantVisibility::Empty
+ } else {
+ VariantVisibility::Visible
+ };
+ variants.push(visibility);
+ }
- ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
+ ConstructorSet::Variants {
+ variants,
+ non_exhaustive: is_declared_nonexhaustive,
+ }
+ }
+ }
+ hir_def::AdtId::UnionId(_) => ConstructorSet::Union,
+ hir_def::AdtId::StructId(_) => {
+ ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) }
+ }
}
}
- TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union,
- TyKind::Adt(..) | TyKind::Tuple(..) => {
- ConstructorSet::Struct { empty: cx.is_uninhabited(ty) }
- }
+ TyKind::Tuple(..) => ConstructorSet::Struct { empty: cx.is_uninhabited(*ty) },
TyKind::Ref(..) => ConstructorSet::Ref,
TyKind::Never => ConstructorSet::NoConstructors,
// This type is one for which we cannot list constructors, like `str` or `f64`.
@@ -492,14 +513,14 @@ impl PatCx for MatchCheckCtx<'_> {
fn report_mixed_deref_pat_ctors(
&self,
- _deref_pat: &DeconstructedPat<'_>,
- _normal_pat: &DeconstructedPat<'_>,
+ _deref_pat: &DeconstructedPat<'a, 'db>,
+ _normal_pat: &DeconstructedPat<'a, 'db>,
) {
// FIXME(deref_patterns): This could report an error comparable to the one in rustc.
}
}
-impl fmt::Debug for MatchCheckCtx<'_> {
+impl fmt::Debug for MatchCheckCtx<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish()
}