Skip to content

Commit c864953

Browse files
committed
Auto merge of #16583 - Veykril:unknown-mismatch, r=Veykril
fix: Don't show type mismatches for `{unknown}` to non-`{unknown}` mismatches Fixes rust-lang/rust-analyzer#15704 Basically we zip the two types, inspecting their substitutions if the constructors are the same, if we encounter a zip step with an `{unknown}` on one side and a non-`{unknown}` on the other we error out and discard the diagnostic. Otherwise we keep it.
2 parents a016555 + fd652ce commit c864953

File tree

3 files changed

+168
-8
lines changed

3 files changed

+168
-8
lines changed

crates/hir-ty/src/infer.rs

+126-5
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::{convert::identity, ops::Index};
2626

2727
use chalk_ir::{
2828
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
29-
Scalar, TyKind, TypeFlags,
29+
Scalar, TyKind, TypeFlags, Variance,
3030
};
3131
use either::Either;
3232
use hir_def::{
@@ -58,8 +58,9 @@ use crate::{
5858
static_lifetime, to_assoc_type_id,
5959
traits::FnTrait,
6060
utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
61-
AliasEq, AliasTy, ClosureId, DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment,
62-
Interner, ProjectionTy, RpitId, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
61+
AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
62+
InEnvironment, Interner, Lifetime, ProjectionTy, RpitId, Substitution, TraitEnvironment,
63+
TraitRef, Ty, TyBuilder, TyExt,
6364
};
6465

6566
// This lint has a false positive here. See the link below for details.
@@ -688,10 +689,17 @@ impl<'a> InferenceContext<'a> {
688689
for ty in type_of_for_iterator.values_mut() {
689690
*ty = table.resolve_completely(ty.clone());
690691
}
691-
for mismatch in type_mismatches.values_mut() {
692+
type_mismatches.retain(|_, mismatch| {
692693
mismatch.expected = table.resolve_completely(mismatch.expected.clone());
693694
mismatch.actual = table.resolve_completely(mismatch.actual.clone());
694-
}
695+
chalk_ir::zip::Zip::zip_with(
696+
&mut UnknownMismatch(self.db),
697+
Variance::Invariant,
698+
&mismatch.expected,
699+
&mismatch.actual,
700+
)
701+
.is_ok()
702+
});
695703
diagnostics.retain_mut(|diagnostic| {
696704
use InferenceDiagnostic::*;
697705
match diagnostic {
@@ -1502,3 +1510,116 @@ impl std::ops::BitOrAssign for Diverges {
15021510
*self = *self | other;
15031511
}
15041512
}
1513+
/// A zipper that checks for unequal `{unknown}` occurrences in the two types. Used to filter out
1514+
/// mismatch diagnostics that only differ in `{unknown}`. These mismatches are usually not helpful.
1515+
/// As the cause is usually an underlying name resolution problem.
1516+
struct UnknownMismatch<'db>(&'db dyn HirDatabase);
1517+
impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> {
1518+
fn zip_tys(&mut self, variance: Variance, a: &Ty, b: &Ty) -> chalk_ir::Fallible<()> {
1519+
let zip_substs = |this: &mut Self,
1520+
variances,
1521+
sub_a: &Substitution,
1522+
sub_b: &Substitution| {
1523+
this.zip_substs(variance, variances, sub_a.as_slice(Interner), sub_b.as_slice(Interner))
1524+
};
1525+
match (a.kind(Interner), b.kind(Interner)) {
1526+
(TyKind::Adt(id_a, sub_a), TyKind::Adt(id_b, sub_b)) if id_a == id_b => zip_substs(
1527+
self,
1528+
Some(self.unification_database().adt_variance(*id_a)),
1529+
sub_a,
1530+
sub_b,
1531+
)?,
1532+
(
1533+
TyKind::AssociatedType(assoc_ty_a, sub_a),
1534+
TyKind::AssociatedType(assoc_ty_b, sub_b),
1535+
) if assoc_ty_a == assoc_ty_b => zip_substs(self, None, sub_a, sub_b)?,
1536+
(TyKind::Tuple(arity_a, sub_a), TyKind::Tuple(arity_b, sub_b))
1537+
if arity_a == arity_b =>
1538+
{
1539+
zip_substs(self, None, sub_a, sub_b)?
1540+
}
1541+
(TyKind::OpaqueType(opaque_ty_a, sub_a), TyKind::OpaqueType(opaque_ty_b, sub_b))
1542+
if opaque_ty_a == opaque_ty_b =>
1543+
{
1544+
zip_substs(self, None, sub_a, sub_b)?
1545+
}
1546+
(TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => self.zip_tys(variance, ty_a, ty_b)?,
1547+
(TyKind::FnDef(fn_def_a, sub_a), TyKind::FnDef(fn_def_b, sub_b))
1548+
if fn_def_a == fn_def_b =>
1549+
{
1550+
zip_substs(
1551+
self,
1552+
Some(self.unification_database().fn_def_variance(*fn_def_a)),
1553+
sub_a,
1554+
sub_b,
1555+
)?
1556+
}
1557+
(TyKind::Ref(mutability_a, _, ty_a), TyKind::Ref(mutability_b, _, ty_b))
1558+
if mutability_a == mutability_b =>
1559+
{
1560+
self.zip_tys(variance, ty_a, ty_b)?
1561+
}
1562+
(TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b))
1563+
if mutability_a == mutability_b =>
1564+
{
1565+
self.zip_tys(variance, ty_a, ty_b)?
1566+
}
1567+
(TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) if const_a == const_b => {
1568+
self.zip_tys(variance, ty_a, ty_b)?
1569+
}
1570+
(TyKind::Closure(id_a, sub_a), TyKind::Closure(id_b, sub_b)) if id_a == id_b => {
1571+
zip_substs(self, None, sub_a, sub_b)?
1572+
}
1573+
(TyKind::Coroutine(coroutine_a, sub_a), TyKind::Coroutine(coroutine_b, sub_b))
1574+
if coroutine_a == coroutine_b =>
1575+
{
1576+
zip_substs(self, None, sub_a, sub_b)?
1577+
}
1578+
(
1579+
TyKind::CoroutineWitness(coroutine_a, sub_a),
1580+
TyKind::CoroutineWitness(coroutine_b, sub_b),
1581+
) if coroutine_a == coroutine_b => zip_substs(self, None, sub_a, sub_b)?,
1582+
(TyKind::Function(fn_ptr_a), TyKind::Function(fn_ptr_b))
1583+
if fn_ptr_a.sig == fn_ptr_b.sig && fn_ptr_a.num_binders == fn_ptr_b.num_binders =>
1584+
{
1585+
zip_substs(self, None, &fn_ptr_a.substitution.0, &fn_ptr_b.substitution.0)?
1586+
}
1587+
(TyKind::Error, TyKind::Error) => (),
1588+
(TyKind::Error, _) | (_, TyKind::Error) => return Err(chalk_ir::NoSolution),
1589+
_ => (),
1590+
}
1591+
1592+
Ok(())
1593+
}
1594+
1595+
fn zip_lifetimes(&mut self, _: Variance, _: &Lifetime, _: &Lifetime) -> chalk_ir::Fallible<()> {
1596+
Ok(())
1597+
}
1598+
1599+
fn zip_consts(&mut self, _: Variance, _: &Const, _: &Const) -> chalk_ir::Fallible<()> {
1600+
Ok(())
1601+
}
1602+
1603+
fn zip_binders<T>(
1604+
&mut self,
1605+
variance: Variance,
1606+
a: &Binders<T>,
1607+
b: &Binders<T>,
1608+
) -> chalk_ir::Fallible<()>
1609+
where
1610+
T: Clone
1611+
+ HasInterner<Interner = Interner>
1612+
+ chalk_ir::zip::Zip<Interner>
1613+
+ TypeFoldable<Interner>,
1614+
{
1615+
chalk_ir::zip::Zip::zip_with(self, variance, a.skip_binders(), b.skip_binders())
1616+
}
1617+
1618+
fn interner(&self) -> Interner {
1619+
Interner
1620+
}
1621+
1622+
fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
1623+
&self.0
1624+
}
1625+
}

crates/hir-ty/src/tests/diagnostics.rs

+42
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use crate::tests::check_no_mismatches;
2+
13
use super::check;
24

35
#[test]
@@ -94,3 +96,43 @@ fn test(x: bool) {
9496
"#,
9597
);
9698
}
99+
100+
#[test]
101+
fn no_mismatches_on_atpit() {
102+
check_no_mismatches(
103+
r#"
104+
//- minicore: option, sized
105+
#![feature(impl_trait_in_assoc_type)]
106+
107+
trait WrappedAssoc {
108+
type Assoc;
109+
fn do_thing(&self) -> Option<Self::Assoc>;
110+
}
111+
112+
struct Foo;
113+
impl WrappedAssoc for Foo {
114+
type Assoc = impl Sized;
115+
116+
fn do_thing(&self) -> Option<Self::Assoc> {
117+
Some(())
118+
}
119+
}
120+
"#,
121+
);
122+
check_no_mismatches(
123+
r#"
124+
//- minicore: option, sized
125+
#![feature(impl_trait_in_assoc_type)]
126+
127+
trait Trait {
128+
type Assoc;
129+
const DEFINE: Option<Self::Assoc>;
130+
}
131+
132+
impl Trait for () {
133+
type Assoc = impl Sized;
134+
const DEFINE: Option<Self::Assoc> = Option::Some(());
135+
}
136+
"#,
137+
);
138+
}

crates/hir-ty/src/tests/simple.rs

-3
Original file line numberDiff line numberDiff line change
@@ -3376,11 +3376,8 @@ fn main() {
33763376
[x,] = &[1,];
33773377
//^^^^expected &[i32; 1], got [{unknown}; _]
33783378
3379-
// FIXME we only want the outermost error, but this matches the current
3380-
// behavior of slice patterns
33813379
let x;
33823380
[(x,),] = &[(1,),];
3383-
// ^^^^expected {unknown}, got ({unknown},)
33843381
//^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
33853382
33863383
let x;

0 commit comments

Comments
 (0)