diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index e4a23cbbac..8665e9d33f 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -25,7 +25,7 @@ use triomphe::Arc;
use typed_arena::Arena;
use crate::{
- Adjust, InferenceResult, Interner, Ty, TyExt, TyKind,
+ Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind,
db::HirDatabase,
diagnostics::match_check::{
self,
@@ -74,8 +74,9 @@ impl BodyValidationDiagnostic {
let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered();
let infer = db.infer(owner);
let body = db.body(owner);
+ let env = db.trait_environment_for_body(owner);
let mut validator =
- ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints };
+ ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints, env };
validator.validate_body(db);
validator.diagnostics
}
@@ -85,6 +86,7 @@ struct ExprValidator {
owner: DefWithBodyId,
body: Arc
,
infer: Arc,
+ env: Arc,
diagnostics: Vec,
validate_lints: bool,
}
@@ -190,7 +192,7 @@ impl ExprValidator {
return;
}
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db);
+ let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
let pattern_arena = Arena::new();
let mut m_arms = Vec::with_capacity(arms.len());
@@ -317,7 +319,7 @@ impl ExprValidator {
return;
};
let pattern_arena = Arena::new();
- let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db);
+ let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
for stmt in &**statements {
let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
continue;
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 785277d70c..dd82a0f45c 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -12,9 +12,10 @@ use rustc_pattern_analysis::{
};
use smallvec::{SmallVec, smallvec};
use stdx::never;
+use triomphe::Arc;
use crate::{
- AdtId, Interner, Scalar, Ty, TyExt, TyKind,
+ AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind,
db::HirDatabase,
infer::normalize,
inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
@@ -69,13 +70,19 @@ pub(crate) struct MatchCheckCtx<'db> {
body: DefWithBodyId,
pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool,
+ env: Arc,
}
impl<'db> MatchCheckCtx<'db> {
- pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
+ pub(crate) fn new(
+ module: ModuleId,
+ body: DefWithBodyId,
+ db: &'db dyn HirDatabase,
+ env: Arc,
+ ) -> Self {
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 }
+ Self { module, body, db, exhaustive_patterns, env }
}
pub(crate) fn compute_match_usefulness(
@@ -100,7 +107,7 @@ impl<'db> MatchCheckCtx<'db> {
}
fn is_uninhabited(&self, ty: &Ty) -> bool {
- is_ty_uninhabited_from(self.db, ty, self.module)
+ is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone())
}
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
@@ -459,8 +466,13 @@ impl PatCx for MatchCheckCtx<'_> {
} 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);
+ let is_uninhabited = is_enum_variant_uninhabited_from(
+ cx.db,
+ variant,
+ subst,
+ cx.module,
+ self.env.clone(),
+ );
let visibility = if is_uninhabited {
VariantVisibility::Empty
} else {
diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs
index e0c3279d3f..e81a5e3c31 100644
--- a/crates/hir-ty/src/inhabitedness.rs
+++ b/crates/hir-ty/src/inhabitedness.rs
@@ -7,17 +7,24 @@ use chalk_ir::{
};
use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility};
use rustc_hash::FxHashSet;
+use triomphe::Arc;
use crate::{
- Binders, Interner, Substitution, Ty, TyKind, consteval::try_const_usize, db::HirDatabase,
+ AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind,
+ consteval::try_const_usize, db::HirDatabase,
};
// FIXME: Turn this into a query, it can be quite slow
/// Checks whether a type is visibly uninhabited from a particular module.
-pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool {
+pub(crate) fn is_ty_uninhabited_from(
+ db: &dyn HirDatabase,
+ ty: &Ty,
+ target_mod: ModuleId,
+ env: Arc,
+) -> bool {
let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
let mut uninhabited_from =
- UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
+ UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
inhabitedness == BREAK_VISIBLY_UNINHABITED
}
@@ -29,11 +36,12 @@ pub(crate) fn is_enum_variant_uninhabited_from(
variant: EnumVariantId,
subst: &Substitution,
target_mod: ModuleId,
+ env: Arc,
) -> bool {
let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
let mut uninhabited_from =
- UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
+ UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst);
inhabitedness == BREAK_VISIBLY_UNINHABITED
}
@@ -44,6 +52,7 @@ struct UninhabitedFrom<'a> {
// guard for preventing stack overflow in non trivial non terminating types
max_depth: usize,
db: &'a dyn HirDatabase,
+ env: Arc,
}
const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(());
@@ -78,6 +87,12 @@ impl TypeVisitor for UninhabitedFrom<'_> {
Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
Some(1..) => item_ty.super_visit_with(self, outer_binder),
},
+ TyKind::Alias(AliasTy::Projection(projection)) => {
+ // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
+ // `TyKind::AssociatedType`, but perhaps in the future it will.
+ let normalized = self.db.normalize_projection(projection.clone(), self.env.clone());
+ self.visit_ty(&normalized, outer_binder)
+ }
_ => CONTINUE_OPAQUELY_INHABITED,
};
self.recursive_ty.remove(ty);
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 7fcc89e518..e6caf2d8d9 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -25,7 +25,7 @@ use syntax::TextRange;
use triomphe::Arc;
use crate::{
- Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
+ Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, TyBuilder, TyExt,
consteval::ConstEvalError,
db::{HirDatabase, InternedClosure, InternedClosureId},
display::{DisplayTarget, HirDisplay, hir_display_with_store},
@@ -79,6 +79,7 @@ struct MirLowerCtx<'db> {
infer: &'db InferenceResult,
resolver: Resolver<'db>,
drop_scopes: Vec,
+ env: Arc,
}
// FIXME: Make this smaller, its stored in database queries
@@ -288,6 +289,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
closures: vec![],
};
let resolver = owner.resolver(db);
+ let env = db.trait_environment_for_body(owner);
MirLowerCtx {
result: mir,
@@ -300,6 +302,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
labeled_loop_blocks: Default::default(),
discr_temp: None,
drop_scopes: vec![DropScope::default()],
+ env,
}
}
@@ -944,10 +947,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
let cast_kind = if source_ty.as_reference().is_some() {
CastKind::PointerCoercion(PointerCast::ArrayToPointer)
} else {
- let mut table = InferenceTable::new(
- self.db,
- self.db.trait_environment_for_body(self.owner),
- );
+ let mut table = InferenceTable::new(self.db, self.env.clone());
cast_kind(&mut table, &source_ty, &target_ty)?
};
@@ -1412,11 +1412,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result {
- let size = || {
- self.db
- .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))
- .map(|it| it.size.bytes_usize())
- };
+ let size =
+ || self.db.layout_of_ty(ty.clone(), self.env.clone()).map(|it| it.size.bytes_usize());
const USIZE_SIZE: usize = size_of::();
let bytes: Box<[_]> = match l {
hir_def::hir::Literal::String(b) => {
@@ -1723,7 +1720,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
fn is_uninhabited(&self, expr_id: ExprId) -> bool {
- is_ty_uninhabited_from(self.db, &self.infer[expr_id], self.owner.module(self.db))
+ is_ty_uninhabited_from(
+ self.db,
+ &self.infer[expr_id],
+ self.owner.module(self.db),
+ self.env.clone(),
+ )
}
/// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
diff --git a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index 35cefd2397..f20b6dea12 100644
--- a/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -106,4 +106,29 @@ fn test(x: Result) {
"#,
);
}
+
+ #[test]
+ fn empty_patterns_normalize() {
+ check_diagnostics(
+ r#"
+enum Infallible {}
+
+trait Foo {
+ type Assoc;
+}
+enum Enum {
+ A,
+ B(T::Assoc),
+}
+
+impl Foo for () {
+ type Assoc = Infallible;
+}
+
+fn foo(v: Enum<()>) {
+ let Enum::A = v;
+}
+ "#,
+ );
+ }
}