Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer.rs')
-rw-r--r--crates/hir-ty/src/infer.rs86
1 files changed, 45 insertions, 41 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 83659dde17..4c860210a9 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -89,6 +89,7 @@ use crate::{
abi::Safety,
infer::{InferCtxt, ObligationInspector, traits::ObligationCause},
},
+ solver_errors::SolverDiagnostic,
utils::TargetFeatureIsSafeInTarget,
};
@@ -459,13 +460,13 @@ pub enum InferenceDiagnostic {
#[type_visitable(ignore)]
expr: ExprId,
},
-}
-
-/// A mismatch between an expected and an inferred type.
-#[derive(Clone, PartialEq, Eq, Debug, Hash, TypeVisitable, TypeFoldable)]
-pub struct TypeMismatch {
- pub expected: StoredTy,
- pub actual: StoredTy,
+ TypeMismatch {
+ #[type_visitable(ignore)]
+ node: ExprOrPatId,
+ expected: StoredTy,
+ found: StoredTy,
+ },
+ SolverDiagnostic(SolverDiagnostic),
}
/// Represents coercing a value to a different type of value.
@@ -685,7 +686,6 @@ pub struct InferenceResult {
pub(crate) type_of_type_placeholder: FxHashMap<TypeRefId, StoredTy>,
pub(crate) type_of_opaque: FxHashMap<InternedOpaqueTyId, StoredTy>,
- pub(crate) type_mismatches: Option<Box<FxHashMap<ExprOrPatId, TypeMismatch>>>,
/// Whether there are any type-mismatching errors in the result.
// FIXME: This isn't as useful as initially thought due to us falling back placeholders to
// `TyKind::Error`.
@@ -693,6 +693,8 @@ pub struct InferenceResult {
pub(crate) has_errors: bool,
/// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
diagnostics: ThinVec<InferenceDiagnostic>,
+ // FIXME: Remove this, change it to be in `InferenceContext`:
+ nodes_with_type_mismatches: Option<Box<FxHashSet<ExprOrPatId>>>,
/// Interned `Error` type to return references to.
// FIXME: Remove this.
@@ -986,12 +988,12 @@ impl InferenceResult {
assoc_resolutions: Default::default(),
tuple_field_access_types: Default::default(),
diagnostics: Default::default(),
+ nodes_with_type_mismatches: Default::default(),
type_of_expr: Default::default(),
type_of_pat: Default::default(),
type_of_binding: Default::default(),
type_of_type_placeholder: Default::default(),
type_of_opaque: Default::default(),
- type_mismatches: Default::default(),
skipped_ref_pats: Default::default(),
has_errors: Default::default(),
error_ty: error_ty.store(),
@@ -1042,26 +1044,22 @@ impl InferenceResult {
ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
}
}
- pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
- self.type_mismatches.as_deref()?.get(&expr.into())
+ pub fn expr_or_pat_has_type_mismatch(&self, node: ExprOrPatId) -> bool {
+ self.nodes_with_type_mismatches.as_ref().is_some_and(|it| it.contains(&node))
}
- pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch> {
- self.type_mismatches.as_deref()?.get(&pat.into())
+ pub fn expr_has_type_mismatch(&self, expr: ExprId) -> bool {
+ self.expr_or_pat_has_type_mismatch(expr.into())
}
- pub fn type_mismatches(&self) -> impl Iterator<Item = (ExprOrPatId, &TypeMismatch)> {
- self.type_mismatches
- .as_deref()
- .into_iter()
- .flatten()
- .map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch))
- }
- pub fn expr_type_mismatches(&self) -> impl Iterator<Item = (ExprId, &TypeMismatch)> {
- self.type_mismatches.as_deref().into_iter().flatten().filter_map(
- |(expr_or_pat, mismatch)| match *expr_or_pat {
- ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
- _ => None,
- },
- )
+ pub fn pat_has_type_mismatch(&self, pat: PatId) -> bool {
+ self.expr_or_pat_has_type_mismatch(pat.into())
+ }
+ pub fn exprs_have_type_mismatches(&self) -> bool {
+ self.nodes_with_type_mismatches
+ .as_ref()
+ .is_some_and(|it| it.iter().any(|node| node.is_expr()))
+ }
+ pub fn has_type_mismatches(&self) -> bool {
+ self.nodes_with_type_mismatches.is_some()
}
pub fn placeholder_types<'db>(&self) -> impl Iterator<Item = (TypeRefId, Ty<'db>)> {
self.type_of_type_placeholder.iter().map(|(&type_ref, ty)| (type_ref, ty.as_ref()))
@@ -1408,7 +1406,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_of_type_placeholder,
type_of_opaque,
skipped_ref_pats,
- type_mismatches,
closures_data,
has_errors,
error_ty: _,
@@ -1418,6 +1415,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
tuple_field_access_types,
coercion_casts: _,
diagnostics: result_diagnostics,
+ nodes_with_type_mismatches,
} = &mut result;
let mut resolver =
WriteBackCtxt::new(table, diagnostics, vars_emitted_type_must_be_known_for);
@@ -1441,12 +1439,9 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_of_type_placeholder.shrink_to_fit();
type_of_opaque.shrink_to_fit();
- if let Some(type_mismatches) = type_mismatches {
+ if let Some(nodes_with_type_mismatches) = nodes_with_type_mismatches {
*has_errors = true;
- for mismatch in type_mismatches.values_mut() {
- resolver.resolve_type_mismatch(mismatch);
- }
- type_mismatches.shrink_to_fit();
+ nodes_with_type_mismatches.shrink_to_fit();
}
for (_, subst) in method_resolutions.values_mut() {
resolver.resolve_completely(subst);
@@ -1938,6 +1933,21 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
if result.is_ty_var() { self.type_must_be_known_at_this_point(node, ty) } else { result }
}
+ pub(crate) fn emit_type_mismatch(
+ &mut self,
+ node: ExprOrPatId,
+ expected: Ty<'db>,
+ found: Ty<'db>,
+ ) {
+ if self.result.nodes_with_type_mismatches.get_or_insert_default().insert(node) {
+ self.diagnostics.push(InferenceDiagnostic::TypeMismatch {
+ node,
+ expected: expected.store(),
+ found: found.store(),
+ });
+ }
+ }
+
fn demand_eqtype(
&mut self,
id: ExprOrPatId,
@@ -1950,10 +1960,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.eq(expected, actual)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
if result.is_err() {
- self.result
- .type_mismatches
- .get_or_insert_default()
- .insert(id, TypeMismatch { expected: expected.store(), actual: actual.store() });
+ self.emit_type_mismatch(id, expected, actual);
}
result.map_err(drop)
}
@@ -1983,10 +1990,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
.sup(expected, actual)
.map(|infer_ok| self.table.register_infer_ok(infer_ok));
if result.is_err() {
- self.result
- .type_mismatches
- .get_or_insert_default()
- .insert(id, TypeMismatch { expected: expected.store(), actual: actual.store() });
+ self.emit_type_mismatch(id, expected, actual);
}
result.map_err(drop)
}