fix: simplify the usage of UnknownMismatch

This commit is contained in:
roife 2024-04-02 02:29:36 +08:00
parent 3d373fec8c
commit 2636e44378
3 changed files with 21 additions and 41 deletions

View file

@ -29,7 +29,6 @@ pub trait TyExt {
fn contains_unknown(&self) -> bool; fn contains_unknown(&self) -> bool;
fn is_ty_var(&self) -> bool; fn is_ty_var(&self) -> bool;
fn is_union(&self) -> bool; fn is_union(&self) -> bool;
fn is_projection(&self) -> bool;
fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
fn as_builtin(&self) -> Option<BuiltinType>; fn as_builtin(&self) -> Option<BuiltinType>;
@ -102,13 +101,6 @@ impl TyExt for Ty {
matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_)))) matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_))))
} }
fn is_projection(&self) -> bool {
matches!(
self.kind(Interner),
TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _)
)
}
fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
match self.kind(Interner) { match self.kind(Interner) {
TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),

View file

@ -704,27 +704,13 @@ impl<'a> InferenceContext<'a> {
type_mismatches.retain(|_, mismatch| { type_mismatches.retain(|_, mismatch| {
mismatch.expected = table.resolve_completely(mismatch.expected.clone()); mismatch.expected = table.resolve_completely(mismatch.expected.clone());
mismatch.actual = table.resolve_completely(mismatch.actual.clone()); mismatch.actual = table.resolve_completely(mismatch.actual.clone());
let unresolved_ty_mismatch = || {
chalk_ir::zip::Zip::zip_with( chalk_ir::zip::Zip::zip_with(
&mut UnknownMismatch(self.db, |ty| matches!(ty.kind(Interner), TyKind::Error)), &mut UnknownMismatch(self.db),
Variance::Invariant, Variance::Invariant,
&mismatch.expected, &mismatch.expected,
&mismatch.actual, &mismatch.actual,
) )
.is_ok() .is_ok()
};
let unresolved_projections_mismatch = || {
chalk_ir::zip::Zip::zip_with(
&mut UnknownMismatch(self.db, |ty| ty.contains_unknown() && ty.is_projection()),
chalk_ir::Variance::Invariant,
&mismatch.expected,
&mismatch.actual,
)
.is_ok()
};
unresolved_ty_mismatch() && unresolved_projections_mismatch()
}); });
diagnostics.retain_mut(|diagnostic| { diagnostics.retain_mut(|diagnostic| {
use InferenceDiagnostic::*; use InferenceDiagnostic::*;
@ -1666,16 +1652,13 @@ impl std::ops::BitOrAssign for Diverges {
*self = *self | other; *self = *self | other;
} }
} }
/// A zipper that checks for unequal `{unknown}` occurrences in the two types.
/// Types that have different constructors are filtered out and tested by the /// A zipper that checks for unequal occurrences of `{unknown}` and unresolved projections
/// provided closure `F`. Commonly used to filter out mismatch diagnostics that /// in the two types. Used to filter out mismatch diagnostics that only differ in
/// only differ in `{unknown}`. These mismatches are usually not helpful, as the /// `{unknown}` and unresolved projections. These mismatches are usually not helpful.
/// cause is usually an underlying name resolution problem. /// As the cause is usually an underlying name resolution problem
/// struct UnknownMismatch<'db>(&'db dyn HirDatabase);
/// E.g. when F is `|ty| matches!(ty.kind(Interer), TyKind::Unknown)`, the zipper impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> {
/// will skip over all mismatches that only differ in `{unknown}`.
struct UnknownMismatch<'db, F: Fn(&Ty) -> bool>(&'db dyn HirDatabase, F);
impl<F: Fn(&Ty) -> bool> chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_, F> {
fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> { fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> {
let zip_substs = |this: &mut Self, let zip_substs = |this: &mut Self,
variances, variances,
@ -1746,7 +1729,12 @@ impl<F: Fn(&Ty) -> bool> chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_,
zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)? zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)?
} }
(TyKind::Error, TyKind::Error) => (), (TyKind::Error, TyKind::Error) => (),
_ if (self.1)(a) || (self.1)(b) => return Err(chalk_ir::NoSolution), (TyKind::Error, _)
| (_, TyKind::Error)
| (TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _), _)
| (_, TyKind::Alias(AliasTy::Projection(_)) | TyKind::AssociatedType(_, _)) => {
return Err(chalk_ir::NoSolution)
}
_ => (), _ => (),
} }

View file

@ -141,7 +141,7 @@ impl Trait for () {
fn no_mismatches_with_unresolved_projections() { fn no_mismatches_with_unresolved_projections() {
check_no_mismatches( check_no_mismatches(
r#" r#"
// Thing is {unknown} // `Thing` is `{unknown}`
fn create() -> Option<(i32, Thing)> { fn create() -> Option<(i32, Thing)> {
Some((69420, Thing)) Some((69420, Thing))
} }