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.rs | 121 |
1 files changed, 67 insertions, 54 deletions
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 0e307feaa8..c61badf179 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, }; @@ -469,13 +470,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. @@ -695,7 +696,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`. @@ -703,6 +703,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. @@ -996,12 +998,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(), @@ -1052,26 +1054,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())) @@ -1418,7 +1416,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: _, @@ -1428,6 +1425,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); @@ -1451,12 +1449,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); @@ -1944,24 +1939,40 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } pub(crate) fn structurally_resolve_type(&mut self, node: ExprOrPatId, ty: Ty<'db>) -> Ty<'db> { - let result = self.table.try_structurally_resolve_type(ty); + let result = self.table.try_structurally_resolve_type(node.into(), ty); 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, expected: Ty<'db>, actual: Ty<'db>, ) -> Result<(), ()> { - let result = self.demand_eqtype_fixme_no_diag(expected, actual); + let result = self + .table + .at(&ObligationCause::new(id)) + .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 + result.map_err(drop) } fn demand_eqtype_fixme_no_diag( @@ -1971,7 +1982,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ) -> Result<(), ()> { let result = self .table - .at(&ObligationCause::new()) + .at(&ObligationCause::dummy()) .eq(expected, actual) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); result.map_err(drop) @@ -1985,14 +1996,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { ) -> Result<(), ()> { let result = self .table - .at(&ObligationCause::new()) + .at(&ObligationCause::new(id)) .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) } @@ -2026,11 +2034,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.types.types.error } - pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>) { + pub(crate) fn require_type_is_sized(&mut self, ty: Ty<'db>, span: Span) { if !ty.references_non_lt_error() && let Some(sized_trait) = self.lang_items.Sized { - self.table.register_bound(ty, sized_trait, ObligationCause::new()); + self.table.register_bound(ty, sized_trait, ObligationCause::new(span)); } } @@ -2095,7 +2103,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { args, ), ); - ty = self.table.try_structurally_resolve_type(alias); + ty = self.table.try_structurally_resolve_type(node.into(), alias); segments = segments.skip(1); } @@ -2195,7 +2203,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { never!("resolver should always resolve lang item paths"); return (self.err_ty(), None); }; - return self.resolve_variant_on_alias(ty, None, mod_path); + return self.resolve_variant_on_alias(node, ty, None, mod_path); }; let mut remaining_segments = path.segments().skip(remaining_idx); @@ -2308,7 +2316,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let ty = self.db.ty(it.into()).instantiate(interner, args); let ty = self.insert_type_vars(ty, Span::Dummy); - self.resolve_variant_on_alias(ty, unresolved, mod_path) + self.resolve_variant_on_alias(node, ty, unresolved, mod_path) } TypeNs::AdtSelfType(_) => { // FIXME this could happen in array size expressions, once we're checking them @@ -2340,12 +2348,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { fn resolve_variant_on_alias( &mut self, + node: ExprOrPatId, ty: Ty<'db>, unresolved: Option<usize>, path: &ModPath, ) -> (Ty<'db>, Option<VariantId>) { let remaining = unresolved.map(|it| path.segments()[it..].len()).filter(|it| it > &0); - let ty = self.table.try_structurally_resolve_type(ty); + let ty = self.table.try_structurally_resolve_type(node.into(), ty); match remaining { None => { let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { @@ -2558,10 +2567,14 @@ impl<'db> Expectation<'db> { /// an expected type. Otherwise, we might write parts of the type /// when checking the 'then' block which are incompatible with the /// 'else' branch. - fn adjust_for_branches(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { + fn adjust_for_branches( + &self, + table: &mut unify::InferenceTable<'db>, + span: Span, + ) -> Expectation<'db> { match *self { Expectation::HasType(ety) => { - let ety = table.try_structurally_resolve_type(ety); + let ety = table.try_structurally_resolve_type(span, ety); if ety.is_ty_var() { Expectation::None } else { Expectation::HasType(ety) } } Expectation::RValueLikeUnsized(ety) => Expectation::RValueLikeUnsized(ety), |