mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 15:15:24 +00:00
fix: silence mismatches involving unresolved projections
This commit is contained in:
parent
899db83128
commit
8d6b65c544
4 changed files with 58 additions and 22 deletions
|
@ -29,6 +29,7 @@ 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>;
|
||||||
|
@ -101,6 +102,13 @@ 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)),
|
||||||
|
|
|
@ -429,6 +429,8 @@ pub struct InferenceResult {
|
||||||
/// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
|
/// Type of the result of `.into_iter()` on the for. `ExprId` is the one of the whole for loop.
|
||||||
pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
|
pub type_of_for_iterator: FxHashMap<ExprId, Ty>,
|
||||||
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
|
||||||
|
/// Whether there are any type-mismatching errors in the result.
|
||||||
|
pub(crate) has_errors: bool,
|
||||||
/// Interned common types to return references to.
|
/// Interned common types to return references to.
|
||||||
standard_types: InternedStandardTypes,
|
standard_types: InternedStandardTypes,
|
||||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||||
|
@ -654,6 +656,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
type_of_rpit,
|
type_of_rpit,
|
||||||
type_of_for_iterator,
|
type_of_for_iterator,
|
||||||
type_mismatches,
|
type_mismatches,
|
||||||
|
has_errors,
|
||||||
standard_types: _,
|
standard_types: _,
|
||||||
pat_adjustments,
|
pat_adjustments,
|
||||||
binding_modes: _,
|
binding_modes: _,
|
||||||
|
@ -695,16 +698,33 @@ impl<'a> InferenceContext<'a> {
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*has_errors = !type_mismatches.is_empty();
|
||||||
|
|
||||||
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),
|
&mut UnknownMismatch(self.db, |ty| matches!(ty.kind(Interner), TyKind::Error)),
|
||||||
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::*;
|
||||||
|
@ -1646,11 +1666,16 @@ impl std::ops::BitOrAssign for Diverges {
|
||||||
*self = *self | other;
|
*self = *self | other;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A zipper that checks for unequal `{unknown}` occurrences in the two types. Used to filter out
|
/// A zipper that checks for unequal `{unknown}` occurrences in the two types.
|
||||||
/// mismatch diagnostics that only differ in `{unknown}`. These mismatches are usually not helpful.
|
/// Types that have different constructors are filtered out and tested by the
|
||||||
/// As the cause is usually an underlying name resolution problem.
|
/// provided closure `F`. Commonly used to filter out mismatch diagnostics that
|
||||||
struct UnknownMismatch<'db>(&'db dyn HirDatabase);
|
/// only differ in `{unknown}`. These mismatches are usually not helpful, as the
|
||||||
impl chalk_ir::zip::Zipper<Interner> for UnknownMismatch<'_> {
|
/// cause is usually an underlying name resolution problem.
|
||||||
|
///
|
||||||
|
/// E.g. when F is `|ty| matches!(ty.kind(Interer), TyKind::Unknown)`, the zipper
|
||||||
|
/// 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,
|
||||||
|
@ -1721,7 +1746,7 @@ impl 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) => (),
|
||||||
(TyKind::Error, _) | (_, TyKind::Error) => return Err(chalk_ir::NoSolution),
|
_ if (self.1)(a) || (self.1)(b) => return Err(chalk_ir::NoSolution),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub enum MirLowerError {
|
||||||
UnresolvedField,
|
UnresolvedField,
|
||||||
UnsizedTemporary(Ty),
|
UnsizedTemporary(Ty),
|
||||||
MissingFunctionDefinition(DefWithBodyId, ExprId),
|
MissingFunctionDefinition(DefWithBodyId, ExprId),
|
||||||
TypeMismatch(TypeMismatch),
|
TypeMismatch(Option<TypeMismatch>),
|
||||||
/// This should never happen. Type mismatch should catch everything.
|
/// This should never happen. Type mismatch should catch everything.
|
||||||
TypeError(&'static str),
|
TypeError(&'static str),
|
||||||
NotSupported(String),
|
NotSupported(String),
|
||||||
|
@ -170,14 +170,15 @@ impl MirLowerError {
|
||||||
body.pretty_print_expr(db.upcast(), *owner, *it)
|
body.pretty_print_expr(db.upcast(), *owner, *it)
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
MirLowerError::TypeMismatch(e) => {
|
MirLowerError::TypeMismatch(e) => match e {
|
||||||
writeln!(
|
Some(e) => writeln!(
|
||||||
f,
|
f,
|
||||||
"Type mismatch: Expected {}, found {}",
|
"Type mismatch: Expected {}, found {}",
|
||||||
e.expected.display(db),
|
e.expected.display(db),
|
||||||
e.actual.display(db),
|
e.actual.display(db),
|
||||||
)?;
|
)?,
|
||||||
}
|
None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?,
|
||||||
|
},
|
||||||
MirLowerError::GenericArgNotProvided(id, subst) => {
|
MirLowerError::GenericArgNotProvided(id, subst) => {
|
||||||
let parent = id.parent;
|
let parent = id.parent;
|
||||||
let param = &db.generic_params(parent).type_or_consts[id.local_id];
|
let param = &db.generic_params(parent).type_or_consts[id.local_id];
|
||||||
|
@ -2152,8 +2153,10 @@ pub fn lower_to_mir(
|
||||||
// need to take this input explicitly.
|
// need to take this input explicitly.
|
||||||
root_expr: ExprId,
|
root_expr: ExprId,
|
||||||
) -> Result<MirBody> {
|
) -> Result<MirBody> {
|
||||||
if let Some((_, it)) = infer.type_mismatches().next() {
|
if infer.has_errors {
|
||||||
return Err(MirLowerError::TypeMismatch(it.clone()));
|
return Err(MirLowerError::TypeMismatch(
|
||||||
|
infer.type_mismatches().next().map(|(_, it)| it.clone()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
|
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
|
||||||
// 0 is return local
|
// 0 is return local
|
||||||
|
|
|
@ -73,8 +73,7 @@ use hir_ty::{
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
|
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
|
||||||
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
|
||||||
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
|
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, WhereClause,
|
||||||
WhereClause,
|
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nameres::diagnostics::DefDiagnosticKind;
|
use nameres::diagnostics::DefDiagnosticKind;
|
||||||
|
@ -1678,6 +1677,7 @@ impl DefWithBody {
|
||||||
for d in &infer.diagnostics {
|
for d in &infer.diagnostics {
|
||||||
acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map));
|
acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pat_or_expr, mismatch) in infer.type_mismatches() {
|
for (pat_or_expr, mismatch) in infer.type_mismatches() {
|
||||||
let expr_or_pat = match pat_or_expr {
|
let expr_or_pat = match pat_or_expr {
|
||||||
ExprOrPatId::ExprId(expr) => source_map.expr_syntax(expr).map(Either::Left),
|
ExprOrPatId::ExprId(expr) => source_map.expr_syntax(expr).map(Either::Left),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue