Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/chalk_ext.rs59
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs154
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs111
-rw-r--r--crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs218
-rw-r--r--crates/hir-ty/src/lib.rs2
5 files changed, 248 insertions, 296 deletions
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index e9960374c6..ea3ed1589d 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -1,32 +1,22 @@
//! Various extensions traits for Chalk types.
-use chalk_ir::Mutability;
use hir_def::{FunctionId, ItemContainerId, Lookup, TraitId};
use crate::{
- AdtId, Binders, CallableDefId, CallableSig, DynTy, Interner, Lifetime, ProjectionTy,
- Substitution, ToChalk, TraitRef, Ty, TyKind, TypeFlags, WhereClause, db::HirDatabase,
- from_assoc_type_id, from_chalk_trait_id, generics::generics, to_chalk_trait_id,
- utils::ClosureSubst,
+ Binders, CallableDefId, CallableSig, DynTy, Interner, ProjectionTy, Substitution, ToChalk,
+ TraitRef, Ty, TyKind, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id,
+ generics::generics, to_chalk_trait_id, utils::ClosureSubst,
};
pub(crate) trait TyExt {
fn is_unit(&self) -> bool;
fn is_unknown(&self) -> bool;
- fn contains_unknown(&self) -> bool;
- fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
fn as_tuple(&self) -> Option<&Substitution>;
fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
- fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
-
- fn strip_references(&self) -> &Ty;
-
- /// If this is a `dyn Trait`, returns that trait.
- fn dyn_trait(&self) -> Option<TraitId>;
}
impl TyExt for Ty {
@@ -38,17 +28,6 @@ impl TyExt for Ty {
matches!(self.kind(Interner), TyKind::Error)
}
- fn contains_unknown(&self) -> bool {
- self.data(Interner).flags.contains(TypeFlags::HAS_ERROR)
- }
-
- fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
- match self.kind(Interner) {
- TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
- _ => None,
- }
- }
-
fn as_tuple(&self) -> Option<&Substitution> {
match self.kind(Interner) {
TyKind::Tuple(_, substs) => Some(substs),
@@ -63,13 +42,6 @@ impl TyExt for Ty {
}
}
- fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
- match self.kind(Interner) {
- TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
- _ => None,
- }
- }
-
fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
match self.kind(Interner) {
&TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
@@ -85,31 +57,6 @@ impl TyExt for Ty {
_ => None,
}
}
-
- fn dyn_trait(&self) -> Option<TraitId> {
- let trait_ref = match self.kind(Interner) {
- // The principal trait bound should be the first element of the bounds. This is an
- // invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
- // FIXME: dyn types may not have principal trait and we don't want to return auto trait
- // here.
- TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().first().and_then(|b| {
- match b.skip_binders() {
- WhereClause::Implemented(trait_ref) => Some(trait_ref),
- _ => None,
- }
- }),
- _ => None,
- }?;
- Some(from_chalk_trait_id(trait_ref.trait_id))
- }
-
- fn strip_references(&self) -> &Ty {
- let mut t: &Ty = self;
- while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(Interner) {
- t = ty;
- }
- t
- }
}
pub trait ProjectionTyExt {
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 7b6fb994ec..0eca0c09d6 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -15,6 +15,7 @@ use intern::sym;
use itertools::Itertools;
use rustc_hash::FxHashSet;
use rustc_pattern_analysis::constructor::Constructor;
+use rustc_type_ir::inherent::{AdtDef, IntoKind};
use syntax::{
AstNode,
ast::{self, UnaryOp},
@@ -23,16 +24,18 @@ use tracing::debug;
use triomphe::Arc;
use typed_arena::Arena;
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
- Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind,
+ Adjust, InferenceResult, TraitEnvironment,
db::HirDatabase,
diagnostics::match_check::{
self,
pat_analysis::{self, DeconstructedPat, MatchCheckCtx, WitnessPat},
},
display::{DisplayTarget, HirDisplay},
+ next_solver::{
+ DbInterner, Ty, TyKind, TypingMode,
+ infer::{DbInternerInferExt, InferCtxt},
+ },
};
pub(crate) use hir_def::{
@@ -77,6 +80,8 @@ impl BodyValidationDiagnostic {
let body = db.body(owner);
let env = db.trait_environment_for_body(owner);
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
+ let infcx =
+ interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, owner.into()));
let mut validator = ExprValidator {
owner,
body,
@@ -84,9 +89,9 @@ impl BodyValidationDiagnostic {
diagnostics: Vec::new(),
validate_lints,
env,
- interner,
+ infcx,
};
- validator.validate_body(db);
+ validator.validate_body();
validator.diagnostics
}
}
@@ -98,11 +103,17 @@ struct ExprValidator<'db> {
env: Arc<TraitEnvironment<'db>>,
diagnostics: Vec<BodyValidationDiagnostic>,
validate_lints: bool,
- interner: DbInterner<'db>,
+ infcx: InferCtxt<'db>,
}
impl<'db> ExprValidator<'db> {
- fn validate_body(&mut self, db: &'db dyn HirDatabase) {
+ #[inline]
+ fn db(&self) -> &'db dyn HirDatabase {
+ self.infcx.interner.db
+ }
+
+ fn validate_body(&mut self) {
+ let db = self.db();
let mut filter_map_next_checker = None;
// we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
let body = Arc::clone(&self.body);
@@ -124,19 +135,19 @@ impl<'db> ExprValidator<'db> {
match expr {
Expr::Match { expr, arms } => {
- self.validate_match(id, *expr, arms, db);
+ self.validate_match(id, *expr, arms);
}
Expr::Call { .. } | Expr::MethodCall { .. } => {
- self.validate_call(db, id, expr, &mut filter_map_next_checker);
+ self.validate_call(id, expr, &mut filter_map_next_checker);
}
Expr::Closure { body: body_expr, .. } => {
self.check_for_trailing_return(*body_expr, &body);
}
Expr::If { .. } => {
- self.check_for_unnecessary_else(id, expr, db);
+ self.check_for_unnecessary_else(id, expr);
}
Expr::Block { .. } | Expr::Async { .. } | Expr::Unsafe { .. } => {
- self.validate_block(db, expr);
+ self.validate_block(expr);
}
_ => {}
}
@@ -157,10 +168,9 @@ impl<'db> ExprValidator<'db> {
fn validate_call(
&mut self,
- db: &dyn HirDatabase,
call_id: ExprId,
expr: &Expr,
- filter_map_next_checker: &mut Option<FilterMapNextChecker>,
+ filter_map_next_checker: &mut Option<FilterMapNextChecker<'db>>,
) {
if !self.validate_lints {
return;
@@ -176,8 +186,9 @@ impl<'db> ExprValidator<'db> {
None => return,
};
- let checker = filter_map_next_checker
- .get_or_insert_with(|| FilterMapNextChecker::new(&self.owner.resolver(db), db));
+ let checker = filter_map_next_checker.get_or_insert_with(|| {
+ FilterMapNextChecker::new(&self.owner.resolver(self.db()), self.db())
+ });
if checker.check(call_id, receiver, &callee).is_some() {
self.diagnostics.push(BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap {
@@ -186,27 +197,20 @@ impl<'db> ExprValidator<'db> {
}
if let Some(receiver_ty) = self.infer.type_of_expr_with_adjust(*receiver) {
- checker.prev_receiver_ty = Some(receiver_ty.to_chalk(self.interner));
+ checker.prev_receiver_ty = Some(receiver_ty);
}
}
}
- fn validate_match(
- &mut self,
- match_expr: ExprId,
- scrutinee_expr: ExprId,
- arms: &[MatchArm],
- db: &dyn HirDatabase,
- ) {
+ fn validate_match(&mut self, match_expr: ExprId, scrutinee_expr: ExprId, arms: &[MatchArm]) {
let Some(scrut_ty) = self.infer.type_of_expr_with_adjust(scrutinee_expr) else {
return;
};
- let scrut_ty = scrut_ty.to_chalk(self.interner);
- if scrut_ty.contains_unknown() {
+ if scrut_ty.references_non_lt_error() {
return;
}
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
let pattern_arena = Arena::new();
let mut m_arms = Vec::with_capacity(arms.len());
@@ -217,8 +221,7 @@ impl<'db> ExprValidator<'db> {
let Some(pat_ty) = self.infer.type_of_pat_with_adjust(arm.pat) else {
return;
};
- let pat_ty = pat_ty.to_chalk(self.interner);
- if pat_ty.contains_unknown() {
+ if pat_ty.references_non_lt_error() {
return;
}
@@ -235,14 +238,14 @@ impl<'db> ExprValidator<'db> {
if (pat_ty == scrut_ty
|| scrut_ty
.as_reference()
- .map(|(match_expr_ty, ..)| *match_expr_ty == pat_ty)
+ .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
.unwrap_or(false))
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
{
// If we had a NotUsefulMatchArm diagnostic, we could
// check the usefulness of each pattern as we added it
// to the matrix here.
- let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
+ let pat = self.lower_pattern(&cx, arm.pat, &mut has_lowering_errors);
let m_arm = pat_analysis::MatchArm {
pat: pattern_arena.alloc(pat),
has_guard: arm.guard.is_some(),
@@ -258,15 +261,12 @@ impl<'db> ExprValidator<'db> {
return;
}
- let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr, db));
- let report = match cx.compute_match_usefulness(
- m_arms.as_slice(),
- scrut_ty.clone(),
- known_valid_scrutinee,
- ) {
- Ok(report) => report,
- Err(()) => return,
- };
+ let known_valid_scrutinee = Some(self.is_known_valid_scrutinee(scrutinee_expr));
+ let report =
+ match cx.compute_match_usefulness(m_arms.as_slice(), scrut_ty, known_valid_scrutinee) {
+ Ok(report) => report,
+ Err(()) => return,
+ };
// FIXME Report unreachable arms
// https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
@@ -277,10 +277,10 @@ impl<'db> ExprValidator<'db> {
match_expr,
uncovered_patterns: missing_match_arms(
&cx,
- &scrut_ty,
+ scrut_ty,
witnesses,
m_arms.is_empty(),
- self.owner.krate(db),
+ self.owner.krate(self.db()),
),
});
}
@@ -291,7 +291,9 @@ impl<'db> ExprValidator<'db> {
// While the above function in rustc uses thir exprs, r-a doesn't have them.
// So, the logic here is getting same result as "hir lowering + match with lowered thir"
// with "hir only"
- fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool {
+ fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId) -> bool {
+ let db = self.db();
+
if self
.infer
.expr_adjustments
@@ -311,20 +313,18 @@ impl<'db> ExprValidator<'db> {
);
value_or_partial.is_none_or(|v| !matches!(v, ValueNs::StaticId(_)))
}
- Expr::Field { expr, .. } => {
- match self.infer.type_of_expr[*expr].to_chalk(self.interner).kind(Interner) {
- TyKind::Adt(adt, ..) if matches!(adt.0, AdtId::UnionId(_)) => false,
- _ => self.is_known_valid_scrutinee(*expr, db),
- }
- }
- Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base, db),
- Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr, db),
+ Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind() {
+ TyKind::Adt(adt, ..) if matches!(adt.def_id().0, AdtId::UnionId(_)) => false,
+ _ => self.is_known_valid_scrutinee(*expr),
+ },
+ Expr::Index { base, .. } => self.is_known_valid_scrutinee(*base),
+ Expr::Cast { expr, .. } => self.is_known_valid_scrutinee(*expr),
Expr::Missing => false,
_ => true,
}
}
- fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
+ fn validate_block(&mut self, expr: &Expr) {
let (Expr::Block { statements, .. }
| Expr::Async { statements, .. }
| Expr::Unsafe { statements, .. }) = expr
@@ -332,7 +332,7 @@ impl<'db> ExprValidator<'db> {
return;
};
let pattern_arena = Arena::new();
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
+ let cx = MatchCheckCtx::new(self.owner.module(self.db()), &self.infcx, self.env.clone());
for stmt in &**statements {
let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
continue;
@@ -342,13 +342,12 @@ impl<'db> ExprValidator<'db> {
}
let Some(initializer) = initializer else { continue };
let Some(ty) = self.infer.type_of_expr_with_adjust(initializer) else { continue };
- let ty = ty.to_chalk(self.interner);
- if ty.contains_unknown() {
+ if ty.references_non_lt_error() {
continue;
}
let mut have_errors = false;
- let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
+ let deconstructed_pat = self.lower_pattern(&cx, pat, &mut have_errors);
// optimization, wildcard trivially hold
if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
@@ -360,7 +359,7 @@ impl<'db> ExprValidator<'db> {
has_guard: false,
arm_data: (),
};
- let report = match cx.compute_match_usefulness(&[match_arm], ty.clone(), None) {
+ let report = match cx.compute_match_usefulness(&[match_arm], ty, None) {
Ok(v) => v,
Err(e) => {
debug!(?e, "match usefulness error");
@@ -373,24 +372,23 @@ impl<'db> ExprValidator<'db> {
pat,
uncovered_patterns: missing_match_arms(
&cx,
- &ty,
+ ty,
witnesses,
false,
- self.owner.krate(db),
+ self.owner.krate(self.db()),
),
});
}
}
}
- fn lower_pattern<'p>(
+ fn lower_pattern<'a>(
&self,
- cx: &MatchCheckCtx<'p>,
+ cx: &MatchCheckCtx<'a, 'db>,
pat: PatId,
- db: &dyn HirDatabase,
have_errors: &mut bool,
- ) -> DeconstructedPat<'p> {
- let mut patcx = match_check::PatCtxt::new(db, &self.infer, &self.body);
+ ) -> DeconstructedPat<'a, 'db> {
+ let mut patcx = match_check::PatCtxt::new(self.db(), &self.infer, &self.body);
let pattern = patcx.lower_pattern(pat);
let pattern = cx.lower_pat(&pattern);
if !patcx.errors.is_empty() {
@@ -434,7 +432,7 @@ impl<'db> ExprValidator<'db> {
}
}
- fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, db: &dyn HirDatabase) {
+ fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr) {
if !self.validate_lints {
return;
}
@@ -453,11 +451,11 @@ impl<'db> ExprValidator<'db> {
&& last_then_expr_ty.is_never()
{
// Only look at sources if the then branch diverges and we have an else branch.
- let source_map = db.body_with_source_map(self.owner).1;
+ let source_map = self.db().body_with_source_map(self.owner).1;
let Ok(source_ptr) = source_map.expr_syntax(id) else {
return;
};
- let root = source_ptr.file_syntax(db);
+ let root = source_ptr.file_syntax(self.db());
let either::Left(ast::Expr::IfExpr(if_expr)) = source_ptr.value.to_node(&root)
else {
return;
@@ -491,15 +489,15 @@ impl<'db> ExprValidator<'db> {
}
}
-struct FilterMapNextChecker {
+struct FilterMapNextChecker<'db> {
filter_map_function_id: Option<hir_def::FunctionId>,
next_function_id: Option<hir_def::FunctionId>,
prev_filter_map_expr_id: Option<ExprId>,
- prev_receiver_ty: Option<chalk_ir::Ty<Interner>>,
+ prev_receiver_ty: Option<Ty<'db>>,
}
-impl FilterMapNextChecker {
- fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
+impl<'db> FilterMapNextChecker<'db> {
+ fn new(resolver: &hir_def::resolver::Resolver<'db>, db: &'db dyn HirDatabase) -> Self {
// Find and store the FunctionIds for Iterator::filter_map and Iterator::next
let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
.resolve_function(db, resolver.krate())
@@ -639,15 +637,19 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
!has_type_mismatches
}
-fn missing_match_arms<'p>(
- cx: &MatchCheckCtx<'p>,
- scrut_ty: &Ty,
- witnesses: Vec<WitnessPat<'p>>,
+fn missing_match_arms<'a, 'db>(
+ cx: &MatchCheckCtx<'a, 'db>,
+ scrut_ty: Ty<'a>,
+ witnesses: Vec<WitnessPat<'a, 'db>>,
arms_is_empty: bool,
krate: Crate,
) -> String {
- struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, DisplayTarget);
- impl fmt::Display for DisplayWitness<'_, '_> {
+ struct DisplayWitness<'a, 'b, 'db>(
+ &'a WitnessPat<'b, 'db>,
+ &'a MatchCheckCtx<'b, 'db>,
+ DisplayTarget,
+ );
+ impl fmt::Display for DisplayWitness<'_, '_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let DisplayWitness(witness, cx, display_target) = *self;
let pat = cx.hoist_witness_pat(witness);
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index af541ffa34..af6795e601 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -9,7 +9,6 @@ mod pat_util;
pub(crate) mod pat_analysis;
-use chalk_ir::Mutability;
use hir_def::{
AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId,
expr_store::{Body, path::Path},
@@ -17,16 +16,16 @@ use hir_def::{
item_tree::FieldsShape,
};
use hir_expand::name::Name;
+use rustc_type_ir::inherent::{IntoKind, SliceLike};
use span::Edition;
use stdx::{always, never};
-use crate::next_solver::DbInterner;
-use crate::next_solver::mapping::NextSolverToChalk;
use crate::{
- InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+ InferenceResult,
db::HirDatabase,
display::{HirDisplay, HirDisplayError, HirFormatter},
infer::BindingMode,
+ next_solver::{GenericArgs, Mutability, Ty, TyKind},
};
use self::pat_util::EnumerateAndAdjustIterator;
@@ -41,46 +40,46 @@ pub(crate) enum PatternError {
}
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct FieldPat {
+pub(crate) struct FieldPat<'db> {
pub(crate) field: LocalFieldId,
- pub(crate) pattern: Pat,
+ pub(crate) pattern: Pat<'db>,
}
#[derive(Clone, Debug, PartialEq)]
-pub(crate) struct Pat {
- pub(crate) ty: Ty,
- pub(crate) kind: Box<PatKind>,
+pub(crate) struct Pat<'db> {
+ pub(crate) ty: Ty<'db>,
+ pub(crate) kind: Box<PatKind<'db>>,
}
/// Close relative to `rustc_mir_build::thir::pattern::PatKind`
#[derive(Clone, Debug, PartialEq)]
-pub(crate) enum PatKind {
+pub(crate) enum PatKind<'db> {
Wild,
Never,
/// `x`, `ref x`, `x @ P`, etc.
Binding {
name: Name,
- subpattern: Option<Pat>,
+ subpattern: Option<Pat<'db>>,
},
/// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
/// multiple variants.
Variant {
- substs: Substitution,
+ substs: GenericArgs<'db>,
enum_variant: EnumVariantId,
- subpatterns: Vec<FieldPat>,
+ subpatterns: Vec<FieldPat<'db>>,
},
/// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
/// a single variant.
Leaf {
- subpatterns: Vec<FieldPat>,
+ subpatterns: Vec<FieldPat<'db>>,
},
/// `&P`, `&mut P`, etc.
Deref {
- subpattern: Pat,
+ subpattern: Pat<'db>,
},
// FIXME: for now, only bool literals are implemented
@@ -91,28 +90,27 @@ pub(crate) enum PatKind {
/// An or-pattern, e.g. `p | q`.
/// Invariant: `pats.len() >= 2`.
Or {
- pats: Vec<Pat>,
+ pats: Vec<Pat<'db>>,
},
}
-pub(crate) struct PatCtxt<'db> {
+pub(crate) struct PatCtxt<'a, 'db> {
db: &'db dyn HirDatabase,
- infer: &'db InferenceResult<'db>,
- body: &'db Body,
+ infer: &'a InferenceResult<'db>,
+ body: &'a Body,
pub(crate) errors: Vec<PatternError>,
- interner: DbInterner<'db>,
}
-impl<'a> PatCtxt<'a> {
+impl<'a, 'db> PatCtxt<'a, 'db> {
pub(crate) fn new(
- db: &'a dyn HirDatabase,
- infer: &'a InferenceResult<'a>,
+ db: &'db dyn HirDatabase,
+ infer: &'a InferenceResult<'db>,
body: &'a Body,
) -> Self {
- Self { db, infer, body, errors: Vec::new(), interner: DbInterner::new_with(db, None, None) }
+ Self { db, infer, body, errors: Vec::new() }
}
- pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat {
+ pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat<'db> {
// XXX(iDawer): Collecting pattern adjustments feels imprecise to me.
// When lowering of & and box patterns are implemented this should be tested
// in a manner of `match_ergonomics_issue_9095` test.
@@ -121,15 +119,12 @@ impl<'a> PatCtxt<'a> {
let unadjusted_pat = self.lower_pattern_unadjusted(pat);
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
unadjusted_pat,
- |subpattern, ref_ty| Pat {
- ty: ref_ty.to_chalk(self.interner).clone(),
- kind: Box::new(PatKind::Deref { subpattern }),
- },
+ |subpattern, ref_ty| Pat { ty: *ref_ty, kind: Box::new(PatKind::Deref { subpattern }) },
)
}
- fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat {
- let mut ty = self.infer[pat].to_chalk(self.interner);
+ fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat<'db> {
+ let mut ty = self.infer[pat];
let variant = self.infer.variant_resolution_for_pat(pat);
let kind = match self.body[pat] {
@@ -142,8 +137,8 @@ impl<'a> PatCtxt<'a> {
}
hir_def::hir::Pat::Tuple { ref args, ellipsis } => {
- let arity = match *ty.kind(Interner) {
- TyKind::Tuple(arity, _) => arity,
+ let arity = match ty.kind() {
+ TyKind::Tuple(tys) => tys.len(),
_ => {
never!("unexpected type for tuple pattern: {:?}", ty);
self.errors.push(PatternError::UnexpectedType);
@@ -156,10 +151,10 @@ impl<'a> PatCtxt<'a> {
hir_def::hir::Pat::Bind { id, subpat, .. } => {
let bm = self.infer.binding_modes[pat];
- ty = self.infer[id].to_chalk(self.interner);
+ ty = self.infer[id];
let name = &self.body[id].name;
- match (bm, ty.kind(Interner)) {
- (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty.clone(),
+ match (bm, ty.kind()) {
+ (BindingMode::Ref(_), TyKind::Ref(_, rty, _)) => ty = rty,
(BindingMode::Ref(_), _) => {
never!(
"`ref {}` has wrong type {:?}",
@@ -167,7 +162,7 @@ impl<'a> PatCtxt<'a> {
ty
);
self.errors.push(PatternError::UnexpectedType);
- return Pat { ty: ty.clone(), kind: PatKind::Wild.into() };
+ return Pat { ty, kind: PatKind::Wild.into() };
}
_ => (),
}
@@ -177,7 +172,7 @@ impl<'a> PatCtxt<'a> {
hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
let expected_len = variant.unwrap().fields(self.db).fields().len();
let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
- self.lower_variant_or_leaf(pat, &ty, subpatterns)
+ self.lower_variant_or_leaf(pat, ty, subpatterns)
}
hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
@@ -193,7 +188,7 @@ impl<'a> PatCtxt<'a> {
})
.collect();
match subpatterns {
- Some(subpatterns) => self.lower_variant_or_leaf(pat, &ty, subpatterns),
+ Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
None => {
self.errors.push(PatternError::MissingField);
PatKind::Wild
@@ -213,7 +208,7 @@ impl<'a> PatCtxt<'a> {
}
};
- Pat { ty: ty.clone(), kind: Box::new(kind) }
+ Pat { ty, kind: Box::new(kind) }
}
fn lower_tuple_subpats(
@@ -221,7 +216,7 @@ impl<'a> PatCtxt<'a> {
pats: &[PatId],
expected_len: usize,
ellipsis: Option<u32>,
- ) -> Vec<FieldPat> {
+ ) -> Vec<FieldPat<'db>> {
if pats.len() > expected_len {
self.errors.push(PatternError::ExtraFields);
return Vec::new();
@@ -236,28 +231,28 @@ impl<'a> PatCtxt<'a> {
.collect()
}
- fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat> {
+ fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat<'db>> {
pats.iter().map(|&p| self.lower_pattern(p)).collect()
}
- fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat> {
+ fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat<'db>> {
pat.map(|p| self.lower_pattern(p))
}
fn lower_variant_or_leaf(
&mut self,
pat: PatId,
- ty: &Ty,
- subpatterns: Vec<FieldPat>,
- ) -> PatKind {
+ ty: Ty<'db>,
+ subpatterns: Vec<FieldPat<'db>>,
+ ) -> PatKind<'db> {
match self.infer.variant_resolution_for_pat(pat) {
Some(variant_id) => {
if let VariantId::EnumVariantId(enum_variant) = variant_id {
- let substs = match ty.kind(Interner) {
- TyKind::Adt(_, substs) => substs.clone(),
+ let substs = match ty.kind() {
+ TyKind::Adt(_, substs) => substs,
kind => {
always!(
- matches!(kind, TyKind::FnDef(..) | TyKind::Error),
+ matches!(kind, TyKind::FnDef(..) | TyKind::Error(_)),
"inappropriate type for def: {:?}",
ty
);
@@ -277,13 +272,13 @@ impl<'a> PatCtxt<'a> {
}
}
- fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat {
- let ty = self.infer[pat].to_chalk(self.interner);
+ fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat<'db> {
+ let ty = self.infer[pat];
- let pat_from_kind = |kind| Pat { ty: ty.clone(), kind: Box::new(kind) };
+ let pat_from_kind = |kind| Pat { ty, kind: Box::new(kind) };
match self.infer.variant_resolution_for_pat(pat) {
- Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, &ty, Vec::new())),
+ Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())),
None => {
self.errors.push(PatternError::UnresolvedVariant);
pat_from_kind(PatKind::Wild)
@@ -291,7 +286,7 @@ impl<'a> PatCtxt<'a> {
}
}
- fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind {
+ fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind<'db> {
use hir_def::hir::{Expr, Literal::Bool};
match self.body[expr] {
@@ -304,7 +299,7 @@ impl<'a> PatCtxt<'a> {
}
}
-impl HirDisplay for Pat {
+impl HirDisplay for Pat<'_> {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match &*self.kind {
PatKind::Wild => write!(f, "_"),
@@ -402,7 +397,7 @@ impl HirDisplay for Pat {
})
});
f.write_joined(subpats, ", ")?;
- if let (TyKind::Tuple(..), 1) = (self.ty.kind(Interner), num_fields) {
+ if let (TyKind::Tuple(..), 1) = (self.ty.kind(), num_fields) {
write!(f, ",")?;
}
write!(f, ")")?;
@@ -411,8 +406,8 @@ impl HirDisplay for Pat {
Ok(())
}
PatKind::Deref { subpattern } => {
- match self.ty.kind(Interner) {
- &TyKind::Ref(mutbl, ..) => {
+ match self.ty.kind() {
+ TyKind::Ref(.., mutbl) => {
write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
}
_ => never!("{:?} is a bad Deref pattern type", self.ty),
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 76f50c1948..f0efadeafc 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -1,28 +1,26 @@
//! 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::{
- DbInterner, TypingMode,
- infer::{DbInternerInferExt, InferCtxt},
- mapping::ChalkToNextSolver,
+ Ty, TyKind,
+ infer::{InferCtxt, traits::ObligationCause},
},
};
@@ -31,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<'a, 'db> = rustc_pattern_analysis::MatchArm<'a, 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.
@@ -70,40 +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: InferCtxt<'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);
- let interner = DbInterner::new_with(db, Some(env.krate), env.block);
- let infcx = interner.infer_ctxt().build(TypingMode::typeck_for_body(interner, body.into()));
- Self { module, body, db, exhaustive_patterns, env, infcx }
+ Self { module, db, exhaustive_patterns, env, infcx }
}
- pub(crate) fn compute_match_usefulness<'a>(
+ pub(crate) fn compute_match_usefulness<'b>(
&self,
- arms: &[MatchArm<'a, 'db>],
- scrut_ty: Ty,
+ arms: &[MatchArm<'a, 'b, 'db>],
+ scrut_ty: Ty<'db>,
known_valid_scrutinee: Option<bool>,
- ) -> Result<UsefulnessReport<'a, 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(());
}
}
@@ -114,13 +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.infcx,
- ty.to_nextsolver(self.infcx.interner),
- 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]`.
@@ -153,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 field_tys = self.db.field_types_ns(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;
@@ -182,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);
@@ -200,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
@@ -253,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..)
@@ -272,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 }
}
@@ -306,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 = ();
@@ -328,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()
}
_ => {
@@ -359,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))
})
@@ -384,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"),
@@ -427,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.infcx,
- variant,
- subst.to_nextsolver(cx.infcx.interner),
- 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`.
@@ -505,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()
}
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 734483a823..eb01ef104b 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -124,7 +124,7 @@ pub use utils::{
};
pub use variance::Variance;
-use chalk_ir::{AdtId, BoundVar, DebruijnIndex, Safety, Scalar};
+use chalk_ir::{BoundVar, DebruijnIndex, Safety, Scalar};
pub(crate) type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;