Unnamed repository; edit this file 'description' to name the repository.
internal: Normalize field type after substituting
iDawer 2021-12-20
parent 1280961 · commit b17aefb
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs1
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs4
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs3
-rw-r--r--crates/hir_ty/src/infer.rs22
-rw-r--r--crates/ide_diagnostics/src/handlers/missing_match_arms.rs24
5 files changed, 50 insertions, 4 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 00c7b95215..a8c4026e31 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -285,6 +285,7 @@ impl ExprValidator {
let pattern_arena = Arena::new();
let cx = MatchCheckCtx {
module: self.owner.module(db.upcast()),
+ body: self.owner,
db,
pattern_arena: &pattern_arena,
};
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
index acb3280329..84ded517ba 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -53,7 +53,7 @@ use smallvec::{smallvec, SmallVec};
use stdx::never;
use syntax::SmolStr;
-use crate::{AdtId, Interner, Scalar, Ty, TyExt, TyKind};
+use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind};
use super::{
usefulness::{helper::Captures, MatchCheckCtx, PatCtxt},
@@ -753,8 +753,8 @@ impl<'p> Fields<'p> {
let fields_len = variant.variant_data(cx.db.upcast()).fields().len() as u32;
(0..fields_len).map(|idx| LocalFieldId::from_raw(idx.into())).filter_map(move |fid| {
- // TODO check ty has been normalized
let ty = field_ty[fid].clone().substitute(Interner, substs);
+ let ty = normalize(cx.db, 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);
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
index 9b00c4dccf..e8a13955d2 100644
--- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
@@ -273,7 +273,7 @@
use std::iter::once;
-use hir_def::{AdtId, HasModule, ModuleId};
+use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId};
use smallvec::{smallvec, SmallVec};
use typed_arena::Arena;
@@ -285,6 +285,7 @@ use self::{helper::Captures, ArmType::*, Usefulness::*};
pub(crate) struct MatchCheckCtx<'a, 'p> {
pub(crate) module: ModuleId,
+ pub(crate) body: DefWithBodyId,
pub(crate) db: &'a dyn HirDatabase,
/// Lowered patterns from arms plus generated by the check.
pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 1bc19323da..95d9a6735a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -16,7 +16,7 @@
use std::ops::Index;
use std::sync::Arc;
-use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar};
+use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use hir_def::{
body::Body,
data::{ConstData, FunctionData, StaticData},
@@ -70,6 +70,26 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
Arc::new(ctx.resolve_all())
}
+/// Fully normalize all the types found within `ty` in context of `owner` body definition.
+///
+/// This is appropriate to use only after type-check: it assumes
+/// that normalization will succeed, for example.
+pub(crate) fn normalize(db: &dyn HirDatabase, owner: DefWithBodyId, ty: Ty) -> Ty {
+ if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
+ return ty;
+ }
+ let krate = owner.module(db.upcast()).krate();
+ let trait_env = owner
+ .as_generic_def_id()
+ .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
+ let mut table = unify::InferenceTable::new(db, trait_env.clone());
+
+ let ty_with_vars = table.normalize_associated_types_in(ty);
+ table.resolve_obligations_as_possible();
+ table.propagate_diverging_flag();
+ table.resolve_completely(ty_with_vars)
+}
+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
enum ExprOrPatId {
ExprId(ExprId),
diff --git a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
index 5a35704697..5ef4d2a226 100644
--- a/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_match_arms.rs
@@ -863,6 +863,30 @@ fn main() {
);
}
+ #[test]
+ fn normalize_field_ty() {
+ check_diagnostics_no_bails(
+ r"
+trait Trait { type Projection; }
+enum E {Foo, Bar}
+struct A;
+impl Trait for A { type Projection = E; }
+struct Next<T: Trait>(T::Projection);
+static __: () = {
+ let n: Next<A> = Next(E::Foo);
+ match n { Next(E::Foo) => {} }
+ // ^ error: missing match arm
+ match n { Next(E::Foo | E::Bar) => {} }
+ match n { Next(E::Foo | _ ) => {} }
+ match n { Next(_ | E::Bar) => {} }
+ match n { _ | Next(E::Bar) => {} }
+ match &n { Next(E::Foo | E::Bar) => {} }
+ match &n { _ | Next(E::Bar) => {} }
+};",
+
+ );
+ }
+
mod false_negatives {
//! The implementation of match checking here is a work in progress. As we roll this out, we
//! prefer false negatives to false positives (ideally there would be no false positives). This