fix: Don't show type mismatches for {unknown}
to non-{unknown}
mismatches
This commit is contained in:
parent
c00c9ee959
commit
fd652ceb73
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
|
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
|
||||||
Scalar, TyKind, TypeFlags,
|
Scalar, TyKind, TypeFlags, Variance,
|
||||||
};
|
};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
@ -58,8 +58,9 @@
|
|||||||
static_lifetime, to_assoc_type_id,
|
static_lifetime, to_assoc_type_id,
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
|
||||||
AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment,
|
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
|
||||||
Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
|
InEnvironment, Interner, Lifetime, ProjectionTy, RpitId, Substitution, TraitEnvironment,
|
||||||
|
TraitRef, Ty, TyBuilder, TyExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
// This lint has a false positive here. See the link below for details.
|
// This lint has a false positive here. See the link below for details.
|
||||||
@ -688,10 +689,17 @@ pub(crate) fn resolve_all(self) -> InferenceResult {
|
|||||||
for ty in type_of_for_iterator.values_mut() {
|
for ty in type_of_for_iterator.values_mut() {
|
||||||
*ty = table.resolve_completely(ty.clone());
|
*ty = table.resolve_completely(ty.clone());
|
||||||
}
|
}
|
||||||
for mismatch in type_mismatches.values_mut() {
|
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());
|
||||||
}
|
chalk_ir::zip::Zip::zip_with(
|
||||||
|
&mut UnknownMismatch(self.db),
|
||||||
|
Variance::Invariant,
|
||||||
|
&mismatch.expected,
|
||||||
|
&mismatch.actual,
|
||||||
|
)
|
||||||
|
.is_ok()
|
||||||
|
});
|
||||||
diagnostics.retain_mut(|diagnostic| {
|
diagnostics.retain_mut(|diagnostic| {
|
||||||
use InferenceDiagnostic::*;
|
use InferenceDiagnostic::*;
|
||||||
match diagnostic {
|
match diagnostic {
|
||||||
@ -1502,3 +1510,116 @@ fn bitor_assign(&mut self, other: Self) {
|
|||||||
*self = *self | other;
|
*self = *self | other;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// A zipper that checks for unequal `{unknown}` occurrences in the two types. Used to filter out
|
||||||
|
/// mismatch diagnostics that only differ in `{unknown}`. These mismatches are usually not helpful.
|
||||||
|
/// As the cause is usually an underlying name resolution problem.
|
||||||
|
struct UnknownMismatch<'db>(&'db dyn HirDatabase);
|
||||||
|
impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> {
|
||||||
|
fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> {
|
||||||
|
let zip_substs = |this: &mut Self,
|
||||||
|
variances,
|
||||||
|
sub_a: &Substitution,
|
||||||
|
sub_b: &Substitution| {
|
||||||
|
this.zip_substs(variance, variances, sub_a.as_slice(Interner), sub_b.as_slice(Interner))
|
||||||
|
};
|
||||||
|
match (a.kind(Interner), b.kind(Interner)) {
|
||||||
|
(TyKind::Adt(id_a, sub_a), TyKind::Adt(id_b, sub_b)) if id_a == id_b => zip_substs(
|
||||||
|
self,
|
||||||
|
Some(self.unification_database().adt_variance(*id_a)),
|
||||||
|
sub_a,
|
||||||
|
sub_b,
|
||||||
|
)?,
|
||||||
|
(
|
||||||
|
TyKind::AssociatedType(assoc_ty_a, sub_a),
|
||||||
|
TyKind::AssociatedType(assoc_ty_b, sub_b),
|
||||||
|
) if assoc_ty_a == assoc_ty_b => zip_substs(self, None, sub_a, sub_b)?,
|
||||||
|
(TyKind::Tuple(arity_a, sub_a), TyKind::Tuple(arity_b, sub_b))
|
||||||
|
if arity_a == arity_b =>
|
||||||
|
{
|
||||||
|
zip_substs(self, None, sub_a, sub_b)?
|
||||||
|
}
|
||||||
|
(TyKind::OpaqueType(opaque_ty_a, sub_a), TyKind::OpaqueType(opaque_ty_b, sub_b))
|
||||||
|
if opaque_ty_a == opaque_ty_b =>
|
||||||
|
{
|
||||||
|
zip_substs(self, None, sub_a, sub_b)?
|
||||||
|
}
|
||||||
|
(TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.zip_tys(variance, ty_a, ty_b)?,
|
||||||
|
(TyKind::FnDef(fn_def_a, sub_a), TyKind::FnDef(fn_def_b, sub_b))
|
||||||
|
if fn_def_a == fn_def_b =>
|
||||||
|
{
|
||||||
|
zip_substs(
|
||||||
|
self,
|
||||||
|
Some(self.unification_database().fn_def_variance(*fn_def_a)),
|
||||||
|
sub_a,
|
||||||
|
sub_b,
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
(TyKind::Ref(mutability_a, _, ty_a), TyKind::Ref(mutability_b, _, ty_b))
|
||||||
|
if mutability_a == mutability_b =>
|
||||||
|
{
|
||||||
|
self.zip_tys(variance, ty_a, ty_b)?
|
||||||
|
}
|
||||||
|
(TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b))
|
||||||
|
if mutability_a == mutability_b =>
|
||||||
|
{
|
||||||
|
self.zip_tys(variance, ty_a, ty_b)?
|
||||||
|
}
|
||||||
|
(TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) if const_a == const_b => {
|
||||||
|
self.zip_tys(variance, ty_a, ty_b)?
|
||||||
|
}
|
||||||
|
(TyKind::Closure(id_a, sub_a), TyKind::Closure(id_b, sub_b)) if id_a == id_b => {
|
||||||
|
zip_substs(self, None, sub_a, sub_b)?
|
||||||
|
}
|
||||||
|
(TyKind::Coroutine(coroutine_a, sub_a), TyKind::Coroutine(coroutine_b, sub_b))
|
||||||
|
if coroutine_a == coroutine_b =>
|
||||||
|
{
|
||||||
|
zip_substs(self, None, sub_a, sub_b)?
|
||||||
|
}
|
||||||
|
(
|
||||||
|
TyKind::CoroutineWitness(coroutine_a, sub_a),
|
||||||
|
TyKind::CoroutineWitness(coroutine_b, sub_b),
|
||||||
|
) if coroutine_a == coroutine_b => zip_substs(self, None, sub_a, sub_b)?,
|
||||||
|
(TyKind::Function(fn_ptr_a), TyKind::Function(fn_ptr_b))
|
||||||
|
if fn_ptr_a.sig == fn_ptr_b.sig && fn_ptr_a.num_binders == fn_ptr_b.num_binders =>
|
||||||
|
{
|
||||||
|
zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)?
|
||||||
|
}
|
||||||
|
(TyKind::Error, TyKind::Error) => (),
|
||||||
|
(TyKind::Error, _) | (_, TyKind::Error) => return Err(chalk_ir::NoSolution),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_lifetimes(&mut self, _: Variance, _: &Lifetime, _: &Lifetime) -> chalk_ir::Fallible<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_consts(&mut self, _: Variance, _: &Const, _: &Const) -> chalk_ir::Fallible<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zip_binders<T>(
|
||||||
|
&mut self,
|
||||||
|
variance: Variance,
|
||||||
|
a: &Binders<T>,
|
||||||
|
b: &Binders<T>,
|
||||||
|
) -> chalk_ir::Fallible<()>
|
||||||
|
where
|
||||||
|
T: Clone
|
||||||
|
+ HasInterner<Interner = Interner>
|
||||||
|
+ chalk_ir::zip::Zip<Interner>
|
||||||
|
+ TypeFoldable<Interner>,
|
||||||
|
{
|
||||||
|
chalk_ir::zip::Zip::zip_with(self, variance, a.skip_binders(), b.skip_binders())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn interner(&self) -> Interner {
|
||||||
|
Interner
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use crate::tests::check_no_mismatches;
|
||||||
|
|
||||||
use super::check;
|
use super::check;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -94,3 +96,43 @@ fn test(x: bool) {
|
|||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_mismatches_on_atpit() {
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
//- minicore: option, sized
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
trait WrappedAssoc {
|
||||||
|
type Assoc;
|
||||||
|
fn do_thing(&self) -> Option<Self::Assoc>;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
impl WrappedAssoc for Foo {
|
||||||
|
type Assoc = impl Sized;
|
||||||
|
|
||||||
|
fn do_thing(&self) -> Option<Self::Assoc> {
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
check_no_mismatches(
|
||||||
|
r#"
|
||||||
|
//- minicore: option, sized
|
||||||
|
#![feature(impl_trait_in_assoc_type)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
type Assoc;
|
||||||
|
const DEFINE: Option<Self::Assoc>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {
|
||||||
|
type Assoc = impl Sized;
|
||||||
|
const DEFINE: Option<Self::Assoc> = Option::Some(());
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3376,11 +3376,8 @@ fn main() {
|
|||||||
[x,] = &[1,];
|
[x,] = &[1,];
|
||||||
//^^^^expected &[i32; 1], got [{unknown}; _]
|
//^^^^expected &[i32; 1], got [{unknown}; _]
|
||||||
|
|
||||||
// FIXME we only want the outermost error, but this matches the current
|
|
||||||
// behavior of slice patterns
|
|
||||||
let x;
|
let x;
|
||||||
[(x,),] = &[(1,),];
|
[(x,),] = &[(1,),];
|
||||||
// ^^^^expected {unknown}, got ({unknown},)
|
|
||||||
//^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
|
//^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
|
||||||
|
|
||||||
let x;
|
let x;
|
||||||
|
Loading…
Reference in New Issue
Block a user