Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/hir-ty/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ hir-expand.workspace = true
base-db.workspace = true
syntax.workspace = true
span.workspace = true
thin-vec = "0.2.14"

[dev-dependencies]
expect-test = "1.5.1"
Expand Down
59 changes: 38 additions & 21 deletions crates/hir-ty/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ use rustc_type_ir::{
};
use span::Edition;
use stdx::never;
use thin_vec::ThinVec;
use triomphe::Arc;

use crate::{
Expand Down Expand Up @@ -489,26 +490,31 @@ pub struct InferenceResult<'db> {
/// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of
/// that which allows us to resolve a [`TupleFieldId`]s type.
tuple_field_access_types: FxHashMap<TupleId, Tys<'db>>,
/// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
diagnostics: Vec<InferenceDiagnostic<'db>>,

pub(crate) type_of_expr: ArenaMap<ExprId, Ty<'db>>,
/// For each pattern record the type it resolves to.
///
/// **Note**: When a pattern type is resolved it may still contain
/// unresolved or missing subpatterns or subpatterns of mismatched types.
pub(crate) type_of_pat: ArenaMap<PatId, Ty<'db>>,
pub(crate) type_of_binding: ArenaMap<BindingId, Ty<'db>>,
pub(crate) type_of_type_placeholder: ArenaMap<TypeRefId, Ty<'db>>,
pub(crate) type_of_type_placeholder: FxHashMap<TypeRefId, Ty<'db>>,
pub(crate) type_of_opaque: FxHashMap<InternedOpaqueTyId, Ty<'db>>,
pub(crate) type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch<'db>>,

pub(crate) type_mismatches: Option<Box<FxHashMap<ExprOrPatId, TypeMismatch<'db>>>>,
/// 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`.
// Which will then mark this field.
pub(crate) has_errors: bool,
/// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead.
diagnostics: ThinVec<InferenceDiagnostic<'db>>,

/// Interned `Error` type to return references to.
// FIXME: Remove this.
error_ty: Ty<'db>,

pub(crate) expr_adjustments: FxHashMap<ExprId, Box<[Adjustment<'db>]>>,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
pub(crate) pat_adjustments: FxHashMap<PatId, Vec<Ty<'db>>>,
/// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
Expand All @@ -525,10 +531,11 @@ pub struct InferenceResult<'db> {
/// ```
/// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
pub(crate) binding_modes: ArenaMap<PatId, BindingMode>,
pub(crate) expr_adjustments: FxHashMap<ExprId, Box<[Adjustment<'db>]>>,

pub(crate) closure_info: FxHashMap<InternedClosureId, (Vec<CapturedItem<'db>>, FnTrait)>,
// FIXME: remove this field
pub mutated_bindings_in_closure: FxHashSet<BindingId>,

pub(crate) coercion_casts: FxHashSet<ExprId>,
}

Expand Down Expand Up @@ -595,25 +602,31 @@ impl<'db> InferenceResult<'db> {
}
}
pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch<'db>> {
self.type_mismatches.get(&expr.into())
self.type_mismatches.as_deref()?.get(&expr.into())
}
pub fn type_mismatch_for_pat(&self, pat: PatId) -> Option<&TypeMismatch<'db>> {
self.type_mismatches.get(&pat.into())
self.type_mismatches.as_deref()?.get(&pat.into())
}
pub fn type_mismatches(&self) -> impl Iterator<Item = (ExprOrPatId, &TypeMismatch<'db>)> {
self.type_mismatches.iter().map(|(expr_or_pat, mismatch)| (*expr_or_pat, mismatch))
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<'db>)> {
self.type_mismatches.iter().filter_map(|(expr_or_pat, mismatch)| match *expr_or_pat {
ExprOrPatId::ExprId(expr) => Some((expr, mismatch)),
_ => None,
})
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 placeholder_types(&self) -> impl Iterator<Item = (TypeRefId, &Ty<'db>)> {
self.type_of_type_placeholder.iter()
self.type_of_type_placeholder.iter().map(|(&type_ref, ty)| (type_ref, ty))
}
pub fn type_of_type_placeholder(&self, type_ref: TypeRefId) -> Option<Ty<'db>> {
self.type_of_type_placeholder.get(type_ref).copied()
self.type_of_type_placeholder.get(&type_ref).copied()
}
pub fn closure_info(&self, closure: InternedClosureId) -> &(Vec<CapturedItem<'db>>, FnTrait) {
self.closure_info.get(&closure).unwrap()
Expand Down Expand Up @@ -1063,13 +1076,14 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
type_of_type_placeholder.shrink_to_fit();
type_of_opaque.shrink_to_fit();

*has_errors |= !type_mismatches.is_empty();

for mismatch in (*type_mismatches).values_mut() {
mismatch.expected = table.resolve_completely(mismatch.expected);
mismatch.actual = table.resolve_completely(mismatch.actual);
if let Some(type_mismatches) = type_mismatches {
*has_errors = true;
for mismatch in type_mismatches.values_mut() {
mismatch.expected = table.resolve_completely(mismatch.expected);
mismatch.actual = table.resolve_completely(mismatch.actual);
}
type_mismatches.shrink_to_fit();
}
type_mismatches.shrink_to_fit();
diagnostics.retain_mut(|diagnostic| {
use InferenceDiagnostic::*;
match diagnostic {
Expand Down Expand Up @@ -1520,7 +1534,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
) -> Result<(), ()> {
let result = self.demand_eqtype_fixme_no_diag(expected, actual);
if result.is_err() {
self.result.type_mismatches.insert(id, TypeMismatch { expected, actual });
self.result
.type_mismatches
.get_or_insert_default()
.insert(id, TypeMismatch { expected, actual });
}
result
}
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/infer/coerce.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {

self.final_ty = Some(icx.types.error);

icx.result.type_mismatches.insert(
icx.result.type_mismatches.get_or_insert_default().insert(
expression.into(),
if label_expression_as_expected {
TypeMismatch { expected: found, actual: expected }
Expand Down
5 changes: 3 additions & 2 deletions crates/hir-ty/src/infer/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use hir_def::expr_store::ExpressionStore;
use hir_def::expr_store::path::Path;
use hir_def::{hir::ExprOrPatId, resolver::Resolver};
use la_arena::{Idx, RawIdx};
use thin_vec::ThinVec;

use crate::{
InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic,
Expand All @@ -24,7 +25,7 @@ use crate::{
// to our resolver and so we cannot have mutable reference, but we really want to have
// ability to dispatch diagnostics during this work otherwise the code becomes a complete mess.
#[derive(Debug, Default, Clone)]
pub(super) struct Diagnostics<'db>(RefCell<Vec<InferenceDiagnostic<'db>>>);
pub(super) struct Diagnostics<'db>(RefCell<ThinVec<InferenceDiagnostic<'db>>>);

impl<'db> Diagnostics<'db> {
pub(super) fn push(&self, diagnostic: InferenceDiagnostic<'db>) {
Expand All @@ -41,7 +42,7 @@ impl<'db> Diagnostics<'db> {
);
}

pub(super) fn finish(self) -> Vec<InferenceDiagnostic<'db>> {
pub(super) fn finish(self) -> ThinVec<InferenceDiagnostic<'db>> {
self.0.into_inner()
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ impl<'db> InferenceContext<'_, 'db> {
if !could_unify {
self.result
.type_mismatches
.get_or_insert_default()
.insert(tgt_expr.into(), TypeMismatch { expected: expected_ty, actual: ty });
}
}
Expand Down Expand Up @@ -100,6 +101,7 @@ impl<'db> InferenceContext<'_, 'db> {
Err(_) => {
self.result
.type_mismatches
.get_or_insert_default()
.insert(expr.into(), TypeMismatch { expected: target, actual: ty });
target
}
Expand Down Expand Up @@ -293,6 +295,7 @@ impl<'db> InferenceContext<'_, 'db> {
if !could_unify {
self.result
.type_mismatches
.get_or_insert_default()
.insert(expr.into(), TypeMismatch { expected: expected_ty, actual: ty });
}
}
Expand Down Expand Up @@ -1188,6 +1191,7 @@ impl<'db> InferenceContext<'_, 'db> {
Err(_) => {
this.result
.type_mismatches
.get_or_insert_default()
.insert(tgt_expr.into(), TypeMismatch { expected: target, actual: ty });
target
}
Expand Down Expand Up @@ -1556,7 +1560,7 @@ impl<'db> InferenceContext<'_, 'db> {
)
.is_err()
{
this.result.type_mismatches.insert(
this.result.type_mismatches.get_or_insert_default().insert(
expr.into(),
TypeMismatch { expected: t, actual: this.types.unit },
);
Expand Down Expand Up @@ -2130,6 +2134,7 @@ impl<'db> InferenceContext<'_, 'db> {
// Don't report type mismatches if there is a mismatch in args count.
self.result
.type_mismatches
.get_or_insert_default()
.insert((*arg).into(), TypeMismatch { expected, actual: found });
}
}
Expand Down
8 changes: 6 additions & 2 deletions crates/hir-ty/src/infer/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ impl<'db> InferenceContext<'_, 'db> {
return self.pat_ty_after_adjustment(pat);
}
Err(_) => {
self.result.type_mismatches.insert(
self.result.type_mismatches.get_or_insert_default().insert(
pat.into(),
TypeMismatch { expected, actual: ty_inserted_vars },
);
Expand Down Expand Up @@ -415,6 +415,7 @@ impl<'db> InferenceContext<'_, 'db> {
Err(_) => {
self.result
.type_mismatches
.get_or_insert_default()
.insert(pat.into(), TypeMismatch { expected, actual: lhs_ty });
// `rhs_ty` is returned so no further type mismatches are
// reported because of this mismatch.
Expand All @@ -431,7 +432,10 @@ impl<'db> InferenceContext<'_, 'db> {
let ty = self.insert_type_vars_shallow(ty);
// FIXME: This never check is odd, but required with out we do inference right now
if !expected.is_never() && !self.unify(ty, expected) {
self.result.type_mismatches.insert(pat.into(), TypeMismatch { expected, actual: ty });
self.result
.type_mismatches
.get_or_insert_default()
.insert(pat.into(), TypeMismatch { expected, actual: ty });
}
self.write_pat_ty(pat, ty);
self.pat_ty_after_adjustment(pat)
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/method_resolution/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
}
Err(_) => {
if self.ctx.unstable_features.arbitrary_self_types {
self.ctx.result.type_mismatches.insert(
self.ctx.result.type_mismatches.get_or_insert_default().insert(
self.expr.into(),
TypeMismatch { expected: method_self_ty, actual: self_ty },
);
Expand Down