diff --git a/Cargo.toml b/Cargo.toml index 8c5071898466..6d61ef9b710f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,6 +160,7 @@ tracing-subscriber = { version = "0.3.19", default-features = false, features = triomphe = { version = "0.1.14", default-features = false, features = ["std"] } url = "2.5.4" xshell = "0.2.7" +thin-vec = "0.2.14" # We need to freeze the version of the crate, as the raw-api feature is considered unstable dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] } diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml index c1c89e8d1cc3..e89a9ce398d4 100644 --- a/crates/hir-def/Cargo.toml +++ b/crates/hir-def/Cargo.toml @@ -30,6 +30,7 @@ text-size.workspace = true salsa.workspace = true salsa-macros.workspace = true query-group.workspace = true +thin-vec.workspace = true ra-ap-rustc_parse_format.workspace = true ra-ap-rustc_abi.workspace = true @@ -44,7 +45,6 @@ mbe.workspace = true cfg.workspace = true tt.workspace = true span.workspace = true -thin-vec = "0.2.14" [dev-dependencies] expect-test.workspace = true diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 9eb7ffe1c719..d2c2da027eb1 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -279,9 +279,9 @@ impl ExprValidator { fn is_known_valid_scrutinee(&self, scrutinee_expr: ExprId, db: &dyn HirDatabase) -> bool { if self .infer - .expr_adjustments - .get(&scrutinee_expr) - .is_some_and(|adjusts| adjusts.iter().any(|a| matches!(a.kind, Adjust::Deref(..)))) + .expr_adjustments(scrutinee_expr) + .iter() + .any(|a| matches!(a.kind, Adjust::Deref(..))) { return false; } diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs index 7df22a45cb4e..11ce2764791a 100644 --- a/crates/hir-ty/src/diagnostics/match_check.rs +++ b/crates/hir-ty/src/diagnostics/match_check.rs @@ -113,13 +113,9 @@ impl<'a> PatCtxt<'a> { // Pattern adjustment is part of RFC 2005-match-ergonomics. // More info https://github.com/rust-lang/rust/issues/42640#issuecomment-313535089 let unadjusted_pat = self.lower_pattern_unadjusted(pat); - self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold( - unadjusted_pat, - |subpattern, ref_ty| Pat { - ty: ref_ty.clone(), - kind: Box::new(PatKind::Deref { subpattern }), - }, - ) + self.infer.pat_adjustments(pat).iter().rev().fold(unadjusted_pat, |subpattern, ref_ty| { + Pat { ty: ref_ty.target.clone(), kind: Box::new(PatKind::Deref { subpattern }) } + }) } fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index e698fb201cb8..407d24f03167 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -23,10 +23,10 @@ mod pat; mod path; pub(crate) mod unify; -use std::{cell::OnceCell, convert::identity, iter, ops::Index}; +use std::{cell::OnceCell, convert::identity, iter, ops::Index, sync::LazyLock}; use chalk_ir::{ - DebruijnIndex, Mutability, Safety, Scalar, TyKind, TypeFlags, Variance, + DebruijnIndex, Mutability, Safety, TyKind, TypeFlags, Variance, cast::Cast, fold::TypeFoldable, interner::HasInterner, @@ -195,6 +195,10 @@ pub enum InferenceTyDiagnosticSource { Signature, } +pub(crate) static ERROR_TY: LazyLock = LazyLock::new(|| TyKind::Error.intern(Interner)); +pub(crate) static UNIT_TY: LazyLock = + LazyLock::new(|| TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner)); + #[derive(Debug)] pub(crate) struct TypeError; pub(crate) type InferResult = Result, TypeError>; @@ -299,24 +303,6 @@ pub struct TypeMismatch { pub actual: Ty, } -#[derive(Clone, PartialEq, Eq, Debug)] -struct InternedStandardTypes { - unknown: Ty, - bool_: Ty, - unit: Ty, - never: Ty, -} - -impl Default for InternedStandardTypes { - fn default() -> Self { - InternedStandardTypes { - unknown: TyKind::Error.intern(Interner), - bool_: TyKind::Scalar(Scalar::Bool).intern(Interner), - unit: TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner), - never: TyKind::Never.intern(Interner), - } - } -} /// Represents coercing a value to a different type of value. /// /// We transform values by following a number of `Adjust` steps in order. @@ -437,6 +423,17 @@ pub enum PointerCast { Unsize, } +#[derive(Clone, PartialEq, Eq, Debug)] +enum Resolution { + Method(FunctionId, Substitution), + Function(FunctionId, Substitution), + Const(ConstId, Substitution), + TypeAlias(TypeAliasId, Substitution), + Field(FieldId), + TupleField(TupleFieldId), + Variant(VariantId), +} + /// The result of type inference: A mapping from expressions and patterns to types. /// /// When you add a field that stores types (including `Substitution` and the like), don't forget @@ -444,20 +441,22 @@ pub enum PointerCast { /// not appear in the final inference result. #[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct InferenceResult { - /// For each method call expr, records the function it resolves to. - method_resolutions: FxHashMap, - /// For each field access expr, records the field it resolves to. - field_resolutions: FxHashMap>, - /// For each struct literal or pattern, records the variant it resolves to. - variant_resolutions: FxHashMap, - /// For each associated item record what it resolves to - assoc_resolutions: FxHashMap, + resolution: FxHashMap, + // /// For each method call expr, records the function it resolves to. + // method_resolutions: FxHashMap, + // /// For each field access expr, records the field it resolves to. + // field_resolutions: FxHashMap>, + // /// For each struct literal or pattern, records the variant it resolves to. + // variant_resolutions: FxHashMap, + // /// For each associated item record what it resolves to + // assoc_resolutions: FxHashMap, /// Whenever a tuple field expression access a tuple field, we allocate a tuple id in /// [`InferenceContext`] and store the tuples substitution there. This map is the reverse of /// that which allows us to resolve a [`TupleFieldId`]s type. pub tuple_field_access_types: FxHashMap, + /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. - pub diagnostics: Vec, + pub diagnostics: Box<[InferenceDiagnostic]>, pub type_of_expr: ArenaMap, /// For each pattern record the type it resolves to. /// @@ -466,19 +465,13 @@ pub struct InferenceResult { pub type_of_pat: ArenaMap, pub type_of_binding: ArenaMap, pub type_of_rpit: ArenaMap, - /// 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, + // FIXME: Option> this type_mismatches: FxHashMap, /// 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, - /// Interned common types to return references to. - // FIXME: Move this into `InferenceContext` - standard_types: InternedStandardTypes, - /// Stores the types which were implicitly dereferenced in pattern binding modes. - pub pat_adjustments: FxHashMap>, /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings. /// /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an @@ -493,7 +486,8 @@ pub struct InferenceResult { /// ``` /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`. pub binding_modes: ArenaMap, - pub expr_adjustments: FxHashMap>, + /// For patterns, this stores the types which were implicitly dereferenced in pattern binding modes. + adjustments: FxHashMap>, pub(crate) closure_info: FxHashMap, FnTrait)>, // FIXME: remove this field pub mutated_bindings_in_closure: FxHashSet, @@ -502,16 +496,35 @@ pub struct InferenceResult { impl InferenceResult { pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> { - self.method_resolutions.get(&expr).cloned() + self.resolution.get(&expr.into()).and_then(|res| match res { + Resolution::Method(id, sub) => Some((*id, sub.clone())), + _ => None, + }) + } + pub fn pat_adjustments(&self, pat: PatId) -> &[Adjustment] { + self.adjustments.get(&ExprOrPatId::PatId(pat)).map_or(&[], |v| v.as_ref()) + } + pub fn expr_adjustments(&self, expr: ExprId) -> &[Adjustment] { + self.adjustments.get(&ExprOrPatId::ExprId(expr)).map_or(&[], |v| v.as_ref()) } pub fn field_resolution(&self, expr: ExprId) -> Option> { - self.field_resolutions.get(&expr).copied() + self.resolution.get(&expr.into()).and_then(|res| match res { + Resolution::Field(id) => Some(Either::Left(*id)), + Resolution::TupleField(id) => Some(Either::Right(*id)), + _ => None, + }) } pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option { - self.variant_resolutions.get(&id.into()).copied() + self.resolution.get(&id.into()).and_then(|res| match res { + Resolution::Variant(id) => Some(*id), + _ => None, + }) } pub fn variant_resolution_for_pat(&self, id: PatId) -> Option { - self.variant_resolutions.get(&id.into()).copied() + self.resolution.get(&id.into()).and_then(|res| match res { + Resolution::Variant(id) => Some(*id), + _ => None, + }) } pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option { match id { @@ -520,10 +533,20 @@ impl InferenceResult { } } pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> { - self.assoc_resolutions.get(&id.into()).cloned() + self.resolution.get(&id.into()).and_then(|res| match *res { + Resolution::TypeAlias(id, ref sub) => Some((id.into(), sub.clone())), + Resolution::Const(id, ref sub) => Some((id.into(), sub.clone())), + Resolution::Function(id, ref sub) => Some((id.into(), sub.clone())), + _ => None, + }) } pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> { - self.assoc_resolutions.get(&id.into()).cloned() + self.resolution.get(&id.into()).and_then(|res| match *res { + Resolution::TypeAlias(id, ref sub) => Some((id.into(), sub.clone())), + Resolution::Const(id, ref sub) => Some((id.into(), sub.clone())), + Resolution::Function(id, ref sub) => Some((id.into(), sub.clone())), + _ => None, + }) } pub fn assoc_resolutions_for_expr_or_pat( &self, @@ -564,7 +587,7 @@ impl Index for InferenceResult { type Output = Ty; fn index(&self, expr: ExprId) -> &Ty { - self.type_of_expr.get(expr).unwrap_or(&self.standard_types.unknown) + self.type_of_expr.get(expr).unwrap_or_else(|| &ERROR_TY) } } @@ -572,7 +595,7 @@ impl Index for InferenceResult { type Output = Ty; fn index(&self, pat: PatId) -> &Ty { - self.type_of_pat.get(pat).unwrap_or(&self.standard_types.unknown) + self.type_of_pat.get(pat).unwrap_or_else(|| &ERROR_TY) } } @@ -580,7 +603,7 @@ impl Index for InferenceResult { type Output = Ty; fn index(&self, id: ExprOrPatId) -> &Ty { - self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown) + self.type_of_expr_or_pat(id).unwrap_or_else(|| &ERROR_TY) } } @@ -588,7 +611,7 @@ impl Index for InferenceResult { type Output = Ty; fn index(&self, b: BindingId) -> &Ty { - self.type_of_binding.get(b).unwrap_or(&self.standard_types.unknown) + self.type_of_binding.get(b).unwrap_or_else(|| &ERROR_TY) } } @@ -756,21 +779,15 @@ impl<'db> InferenceContext<'db> { // Destructure every single field so whenever new fields are added to `InferenceResult` we // don't forget to handle them here. let InferenceResult { - method_resolutions, - field_resolutions: _, - variant_resolutions: _, - assoc_resolutions, + resolution, type_of_expr, type_of_pat, type_of_binding, type_of_rpit, - type_of_for_iterator, type_mismatches, has_errors, - standard_types: _, - pat_adjustments, binding_modes: _, - expr_adjustments, + adjustments, // Types in `closure_info` have already been `resolve_completely()`'d during // `InferenceContext::infer_closures()` (in `HirPlace::ty()` specifically), so no need // to resolve them here. @@ -786,7 +803,7 @@ impl<'db> InferenceContext<'db> { // Even though coercion casts provide type hints, we check casts after fallback for // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. let mut apply_adjustments = |expr, adj: Vec<_>| { - expr_adjustments.insert(expr, adj.into_boxed_slice()); + adjustments.insert(ExprOrPatId::ExprId(expr), adj.into_boxed_slice()); }; let mut set_coercion_cast = |expr| { coercion_casts.insert(expr); @@ -824,11 +841,6 @@ impl<'db> InferenceContext<'db> { *has_errors = *has_errors || ty.contains_unknown(); } type_of_rpit.shrink_to_fit(); - for ty in type_of_for_iterator.values_mut() { - *ty = table.resolve_completely(ty.clone()); - *has_errors = *has_errors || ty.contains_unknown(); - } - type_of_for_iterator.shrink_to_fit(); *has_errors |= !type_mismatches.is_empty(); @@ -873,28 +885,25 @@ impl<'db> InferenceContext<'db> { true }); diagnostics.shrink_to_fit(); - for (_, subst) in method_resolutions.values_mut() { - *subst = table.resolve_completely(subst.clone()); - *has_errors = - *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); - } - method_resolutions.shrink_to_fit(); - for (_, subst) in assoc_resolutions.values_mut() { - *subst = table.resolve_completely(subst.clone()); - *has_errors = - *has_errors || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + for it in resolution.values_mut() { + match it { + Resolution::Method(_, subst) + | Resolution::Function(_, subst) + | Resolution::Const(_, subst) + | Resolution::TypeAlias(_, subst) => { + *subst = table.resolve_completely(subst.clone()); + *has_errors = *has_errors + || subst.type_parameters(Interner).any(|ty| ty.contains_unknown()); + } + Resolution::Variant(_) | Resolution::Field(_) | Resolution::TupleField(_) => (), + } } - assoc_resolutions.shrink_to_fit(); - for adjustment in expr_adjustments.values_mut().flatten() { + resolution.shrink_to_fit(); + for adjustment in adjustments.values_mut().flatten() { adjustment.target = table.resolve_completely(adjustment.target.clone()); *has_errors = *has_errors || adjustment.target.contains_unknown(); } - expr_adjustments.shrink_to_fit(); - for adjustment in pat_adjustments.values_mut().flatten() { - *adjustment = table.resolve_completely(adjustment.clone()); - *has_errors = *has_errors || adjustment.contains_unknown(); - } - pat_adjustments.shrink_to_fit(); + adjustments.shrink_to_fit(); result.tuple_field_access_types = tuple_field_accesses_rev .into_iter() .enumerate() @@ -906,7 +915,7 @@ impl<'db> InferenceContext<'db> { .collect(); result.tuple_field_access_types.shrink_to_fit(); - result.diagnostics = diagnostics; + result.diagnostics = diagnostics.into_boxed_slice(); result } @@ -1022,7 +1031,7 @@ impl<'db> InferenceContext<'db> { return_ty } } - None => self.result.standard_types.unit.clone(), + None => UNIT_TY.clone(), }; self.return_ty = self.normalize_associated_types_in(return_ty); @@ -1277,7 +1286,7 @@ impl<'db> InferenceContext<'db> { if adjustments.is_empty() { return; } - match self.result.expr_adjustments.entry(expr) { + match self.result.adjustments.entry(expr.into()) { std::collections::hash_map::Entry::Occupied(mut entry) => { match (&mut entry.get_mut()[..], &adjustments[..]) { ( @@ -1300,15 +1309,25 @@ impl<'db> InferenceContext<'db> { } fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) { - self.result.method_resolutions.insert(expr, (func, subst)); + self.result.resolution.insert(expr.into(), Resolution::Method(func, subst)); } fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) { - self.result.variant_resolutions.insert(id, variant); + self.result.resolution.insert(id, Resolution::Variant(variant)); } fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: AssocItemId, subs: Substitution) { - self.result.assoc_resolutions.insert(id, (item, subs)); + match item { + AssocItemId::FunctionId(function_id) => { + self.result.resolution.insert(id, Resolution::Function(function_id, subs)) + } + AssocItemId::ConstId(const_id) => { + self.result.resolution.insert(id, Resolution::Const(const_id, subs)) + } + AssocItemId::TypeAliasId(type_alias_id) => { + self.result.resolution.insert(id, Resolution::TypeAlias(type_alias_id, subs)) + } + }; } fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { @@ -1400,7 +1419,7 @@ impl<'db> InferenceContext<'db> { } fn err_ty(&self) -> Ty { - self.result.standard_types.unknown.clone() + TyKind::Error.intern(Interner) } fn make_body_lifetime(&mut self, lifetime_ref: LifetimeRefId) -> Lifetime { diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index bd57ca891620..efaa0b0d6502 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -35,7 +35,7 @@ use crate::{ db::{HirDatabase, InternedClosure, InternedCoroutine}, error_lifetime, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx, generics::Generics, - infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever}, + infer::{BreakableKind, CoerceMany, Diverges, ERROR_TY, UNIT_TY, coerce::CoerceNever}, make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, to_assoc_type_id, to_chalk_trait_id, @@ -82,7 +82,7 @@ impl InferenceContext<'_> { // When `sig_tys.len() == 1` the first type is the return type, not the // first parameter type. Some(ty) if sig_tys.len() > 1 => ty.assert_ty_ref(Interner).clone(), - _ => self.result.standard_types.unit.clone(), + _ => UNIT_TY.clone(), }; let yield_ty = self.table.new_type_var(); @@ -337,7 +337,7 @@ impl InferenceContext<'_> { .map(to_chalk_trait_id) .collect(); - let self_ty = self.result.standard_types.unknown.clone(); + let self_ty = ERROR_TY.clone(); let bounds = dyn_ty.bounds.clone().substitute(Interner, &[self_ty.cast(Interner)]); for bound in bounds.iter(Interner) { // NOTE(skip_binders): the extracted types are rebound by the returned `FnPointer` @@ -905,8 +905,7 @@ impl CapturedItemWithoutTy { impl InferenceContext<'_> { fn place_of_expr(&mut self, tgt_expr: ExprId) -> Option { let r = self.place_of_expr_without_adjust(tgt_expr)?; - let adjustments = - self.result.expr_adjustments.get(&tgt_expr).map(|it| &**it).unwrap_or_default(); + let adjustments = self.result.expr_adjustments(tgt_expr); apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments) } @@ -1087,12 +1086,12 @@ impl InferenceContext<'_> { } fn walk_expr(&mut self, tgt_expr: ExprId) { - if let Some(it) = self.result.expr_adjustments.get_mut(&tgt_expr) { + if let Some(it) = self.result.adjustments.get_mut(&tgt_expr.into()) { // FIXME: this take is completely unneeded, and just is here to make borrow checker // happy. Remove it if you can. let x_taken = mem::take(it); self.walk_expr_with_adjust(tgt_expr, &x_taken); - *self.result.expr_adjustments.get_mut(&tgt_expr).unwrap() = x_taken; + *self.result.adjustments.get_mut(&tgt_expr.into()).unwrap() = x_taken; } else { self.walk_expr_without_adjust(tgt_expr); } @@ -1389,7 +1388,7 @@ impl InferenceContext<'_> { }, }, } - if self.result.pat_adjustments.get(&p).is_some_and(|it| !it.is_empty()) { + if !self.result.pat_adjustments(p).is_empty() { for_mut = BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }; } self.body.walk_pats_shallow(p, |p| self.walk_pat_inner(p, update_result, for_mut)); @@ -1401,10 +1400,8 @@ impl InferenceContext<'_> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(it) = self.result.expr_adjustments.get(&e) { - if let Some(it) = it.last() { - ty = Some(it.target.clone()); - } + if let Some(it) = self.result.expr_adjustments(e).last() { + ty = Some(it.target.clone()); } ty.unwrap_or_else(|| self.expr_ty(e)) } @@ -1515,8 +1512,7 @@ impl InferenceContext<'_> { } fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) { - let adjustments_count = - self.result.pat_adjustments.get(&tgt_pat).map(|it| it.len()).unwrap_or_default(); + let adjustments_count = self.result.pat_adjustments(tgt_pat).len(); place.projections.extend((0..adjustments_count).map(|_| ProjectionElem::Deref)); self.current_capture_span_stack .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat))); @@ -1736,8 +1732,12 @@ impl InferenceContext<'_> { for (derefed_callee, callee_ty, params, expr) in exprs { if let &Expr::Call { callee, .. } = &self.body[expr] { - let mut adjustments = - self.result.expr_adjustments.remove(&callee).unwrap_or_default().into_vec(); + let mut adjustments = self + .result + .adjustments + .remove(&callee.into()) + .unwrap_or_default() + .into_vec(); self.write_fn_trait_method_resolution( kind, &derefed_callee, @@ -1746,7 +1746,7 @@ impl InferenceContext<'_> { ¶ms, expr, ); - self.result.expr_adjustments.insert(callee, adjustments.into_boxed_slice()); + self.result.adjustments.insert(callee.into(), adjustments.into_boxed_slice()); } } } diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index 39bd90849fe8..864b46f54f8d 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -19,7 +19,7 @@ use crate::{ db::HirDatabase, infer::{ Adjust, Adjustment, AutoBorrow, InferOk, InferenceContext, OverloadedDeref, PointerCast, - TypeError, TypeMismatch, + TypeError, TypeMismatch, UNIT_TY, }, utils::ClosureSubst, }; @@ -85,12 +85,8 @@ impl CoerceMany { self.final_ty.clone().unwrap_or_else(|| self.expected_ty.clone()) } - pub(super) fn complete(self, ctx: &mut InferenceContext<'_>) -> Ty { - if let Some(final_ty) = self.final_ty { - final_ty - } else { - ctx.result.standard_types.never.clone() - } + pub(super) fn complete(self) -> Ty { + if let Some(final_ty) = self.final_ty { final_ty } else { TyKind::Never.intern(Interner) } } pub(super) fn coerce_forced_unit( @@ -98,7 +94,7 @@ impl CoerceMany { ctx: &mut InferenceContext<'_>, cause: CoercionCause, ) { - self.coerce(ctx, None, &ctx.result.standard_types.unit.clone(), cause) + self.coerce(ctx, None, &UNIT_TY.clone(), cause) } /// Merge two types from different branches, with possible coercion. @@ -164,7 +160,7 @@ impl CoerceMany { // - [Comment from rustc](https://github.com/rust-lang/rust/blob/5ff18d0eaefd1bd9ab8ec33dab2404a44e7631ed/compiler/rustc_hir_typeck/src/coercion.rs#L1334-L1335) // First try to coerce the new expression to the type of the previous ones, // but only if the new expression has no coercion already applied to it. - if expr.is_none_or(|expr| !ctx.result.expr_adjustments.contains_key(&expr)) { + if expr.is_none_or(|expr| !ctx.result.adjustments.contains_key(&expr.into())) { if let Ok(res) = ctx.coerce(expr, &expr_ty, &self.merged_ty(), CoerceNever::Yes) { self.final_ty = Some(res); if let Some(expr) = expr { diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 87b7f3406ff7..972750991ad2 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -30,7 +30,7 @@ use crate::{ consteval, generics::generics, infer::{ - BreakableKind, + BreakableKind, ERROR_TY, Resolution, UNIT_TY, coerce::{CoerceMany, CoerceNever, CoercionCause}, find_continuable, pat::contains_explicit_ref_binding, @@ -250,12 +250,10 @@ impl InferenceContext<'_> { // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from `!` to `expected`. if ty.is_never() { - if let Some(adjustments) = self.result.expr_adjustments.get(&expr) { - return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &**adjustments { - target.clone() - } else { - self.err_ty() - }; + match self.result.expr_adjustments(expr) { + [Adjustment { kind: Adjust::NeverToAny, target }] => return target.clone(), + [_, ..] => return self.err_ty(), + [] => (), } if let Some(target) = expected.only_has_type(&mut self.table) { @@ -292,7 +290,7 @@ impl InferenceContext<'_> { let expected = &expected.adjust_for_branches(&mut self.table); self.infer_expr_coerce_never( condition, - &Expectation::HasType(self.result.standard_types.bool_.clone()), + &Expectation::HasType(TyKind::Scalar(Scalar::Bool).intern(Interner)), ExprIsRead::Yes, ); @@ -320,7 +318,7 @@ impl InferenceContext<'_> { } } - coerce.complete(self) + coerce.complete() } &Expr::Let { pat, expr } => { let child_is_read = if self.pat_guaranteed_to_constitute_read_for_never(pat) { @@ -334,7 +332,7 @@ impl InferenceContext<'_> { &input_ty, Some(DeclContext { origin: DeclOrigin::LetExpr }), ); - self.result.standard_types.bool_.clone() + TyKind::Scalar(Scalar::Bool).intern(Interner) } Expr::Block { statements, tail, label, id } => { self.infer_block(tgt_expr, *id, statements, *tail, *label, expected) @@ -369,7 +367,7 @@ impl InferenceContext<'_> { self.diverges = Diverges::Maybe; breaks } - None => self.result.standard_types.never.clone(), + None => TyKind::Never.intern(Interner), } } Expr::Closure { body, args, ret_type, arg_types, closure_kind, capture_by: _ } => self @@ -394,7 +392,7 @@ impl InferenceContext<'_> { if arms.is_empty() { self.diverges = Diverges::Always; - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } else { let matchee_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let mut all_arms_diverge = Diverges::Always; @@ -407,9 +405,7 @@ impl InferenceContext<'_> { let result_ty = match &expected { // We don't coerce to `()` so that if the match expression is a // statement it's branches can have any consistent type. - Expectation::HasType(ty) if *ty != self.result.standard_types.unit => { - ty.clone() - } + Expectation::HasType(ty) if !ty.is_unit() => ty.clone(), _ => self.table.new_type_var(), }; let mut coerce = CoerceMany::new(result_ty); @@ -419,7 +415,9 @@ impl InferenceContext<'_> { self.diverges = Diverges::Maybe; self.infer_expr_coerce_never( guard_expr, - &Expectation::HasType(self.result.standard_types.bool_.clone()), + &Expectation::HasType( + TyKind::Scalar(Scalar::Bool).intern(Interner), + ), ExprIsRead::Yes, ); } @@ -432,7 +430,7 @@ impl InferenceContext<'_> { self.diverges = matchee_diverges | all_arms_diverge; - coerce.complete(self) + coerce.complete() } } Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr), @@ -444,7 +442,7 @@ impl InferenceContext<'_> { bad_value_break: false, }); }; - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } &Expr::Break { expr, label } => { let val_ty = if let Some(expr) = expr { @@ -496,7 +494,7 @@ impl InferenceContext<'_> { }); } } - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } &Expr::Return { expr } => self.infer_expr_return(tgt_expr, expr), &Expr::Become { expr } => self.infer_expr_become(expr), @@ -509,20 +507,20 @@ impl InferenceContext<'_> { ExprIsRead::Yes, ); } else { - let unit = self.result.standard_types.unit.clone(); + let unit = UNIT_TY.clone(); let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty, CoerceNever::Yes); } resume_ty } else { // FIXME: report error (yield expr in non-coroutine) - self.result.standard_types.unknown.clone() + ERROR_TY.clone() } } Expr::Yeet { expr } => { if let &Some(expr) = expr { self.infer_expr_no_expect(expr, ExprIsRead::Yes); } - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } Expr::RecordLit { path, fields, spread, .. } => { let (ty, def_id) = self.resolve_variant(tgt_expr.into(), path.as_deref(), false); @@ -702,16 +700,16 @@ impl InferenceContext<'_> { } Expr::BinaryOp { lhs, rhs, op } => match op { Some(BinaryOp::LogicOp(_)) => { - let bool_ty = self.result.standard_types.bool_.clone(); + let bool_ty = TyKind::Scalar(Scalar::Bool).intern(Interner); self.infer_expr_coerce( *lhs, - &Expectation::HasType(bool_ty.clone()), + &Expectation::HasType(TyKind::Scalar(Scalar::Bool).intern(Interner)), ExprIsRead::Yes, ); let lhs_diverges = self.diverges; self.infer_expr_coerce( *rhs, - &Expectation::HasType(bool_ty.clone()), + &Expectation::HasType(TyKind::Scalar(Scalar::Bool).intern(Interner)), ExprIsRead::Yes, ); // Depending on the LHS' value, the RHS can never execute. @@ -748,7 +746,7 @@ impl InferenceContext<'_> { self.inside_assignment = false; self.resolver.reset_to_guard(resolver_guard); } - self.result.standard_types.unit.clone() + UNIT_TY.clone() } Expr::Range { lhs, rhs, range_type } => { let lhs_ty = @@ -862,7 +860,7 @@ impl InferenceContext<'_> { } Expr::Array(array) => self.infer_expr_array(array, expected), Expr::Literal(lit) => match lit { - Literal::Bool(..) => self.result.standard_types.bool_.clone(), + Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner), Literal::String(..) => { TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(Interner)) .intern(Interner) @@ -1004,7 +1002,7 @@ impl InferenceContext<'_> { AsmOperand::Label(expr) => { self.infer_expr( expr, - &Expectation::HasType(self.result.standard_types.unit.clone()), + &Expectation::HasType(UNIT_TY.clone()), ExprIsRead::No, ); } @@ -1014,11 +1012,7 @@ impl InferenceContext<'_> { // FIXME: `sym` should report for things that are not functions or statics. AsmOperand::Sym(_) => (), }); - if diverge { - self.result.standard_types.never.clone() - } else { - self.result.standard_types.unit.clone() - } + if diverge { TyKind::Never.intern(Interner) } else { UNIT_TY.clone() } } }; // use a new type variable if we got unknown here @@ -1182,7 +1176,7 @@ impl InferenceContext<'_> { coerce.coerce(self, Some(expr), &cur_elem_ty, CoercionCause::Expr(expr)); } ( - coerce.complete(self), + coerce.complete(), consteval::usize_const(self.db, Some(elements.len() as u128), krate), ) } @@ -1247,7 +1241,7 @@ impl InferenceContext<'_> { } } } - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } fn infer_expr_become(&mut self, expr: ExprId) -> Ty { @@ -1271,7 +1265,7 @@ impl InferenceContext<'_> { } } - self.result.standard_types.never.clone() + TyKind::Never.intern(Interner) } fn infer_expr_box(&mut self, inner_expr: ExprId, expected: &Expectation) -> Ty { @@ -1461,7 +1455,7 @@ impl InferenceContext<'_> { mem::replace(&mut this.diverges, Diverges::Maybe); this.infer_expr_coerce( *expr, - &Expectation::HasType(this.result.standard_types.never.clone()), + &Expectation::HasType(TyKind::Never.intern(Interner)), ExprIsRead::Yes, ); this.diverges = previous_diverges; @@ -1473,7 +1467,7 @@ impl InferenceContext<'_> { } else { this.infer_expr_coerce( expr, - &Expectation::HasType(this.result.standard_types.unit.clone()), + &Expectation::HasType(UNIT_TY.clone()), ExprIsRead::Yes, ); } @@ -1504,26 +1498,15 @@ impl InferenceContext<'_> { } else { CoerceNever::No }; - if this - .coerce( - Some(expr), - &this.result.standard_types.unit.clone(), - &t, - coerce_never, - ) - .is_err() - { + if this.coerce(Some(expr), &UNIT_TY.clone(), &t, coerce_never).is_err() { this.result.type_mismatches.insert( expr.into(), - TypeMismatch { - expected: t.clone(), - actual: this.result.standard_types.unit.clone(), - }, + TypeMismatch { expected: t.clone(), actual: UNIT_TY.clone() }, ); } t } else { - this.result.standard_types.unit.clone() + UNIT_TY.clone() } } }); @@ -1634,7 +1617,10 @@ impl InferenceContext<'_> { match self.lookup_field(&receiver_ty, name) { Some((ty, field_id, adjustments, is_public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); - self.result.field_resolutions.insert(tgt_expr, field_id); + self.result.resolution.insert( + tgt_expr.into(), + field_id.either(Resolution::Field, Resolution::TupleField), + ); if !is_public { if let Either::Left(field) = field_id { // FIXME: Merge this diagnostic into UnresolvedField? @@ -1835,7 +1821,10 @@ impl InferenceContext<'_> { { Some((ty, field_id, adjustments, _public)) => { self.write_expr_adj(receiver, adjustments.into_boxed_slice()); - self.result.field_resolutions.insert(tgt_expr, field_id); + self.result.resolution.insert( + tgt_expr.into(), + field_id.either(Resolution::Field, Resolution::TupleField), + ); Some(ty) } None => None, @@ -2311,7 +2300,7 @@ impl InferenceContext<'_> { let output_ty = match op { BinaryOp::LogicOp(_) => { - let bool_ = self.result.standard_types.bool_.clone(); + let bool_ = TyKind::Scalar(Scalar::Bool).intern(Interner); self.unify(&lhs, &bool_); self.unify(&rhs, &bool_); bool_ @@ -2331,7 +2320,7 @@ impl InferenceContext<'_> { BinaryOp::CmpOp(_) => { // LHS and RHS will have the same type self.unify(&lhs, &rhs); - self.result.standard_types.bool_.clone() + TyKind::Scalar(Scalar::Bool).intern(Interner) } BinaryOp::Assignment { op: None } => { @@ -2342,7 +2331,7 @@ impl InferenceContext<'_> { BinaryOp::Assignment { .. } => unreachable!("handled above"), }; - if is_assign { self.result.standard_types.unit.clone() } else { output_ty } + if is_assign { UNIT_TY.clone() } else { output_ty } } fn is_builtin_binop(&mut self, lhs: &Ty, rhs: &Ty, op: BinaryOp) -> bool { @@ -2416,6 +2405,6 @@ impl InferenceContext<'_> { }); let res = cb(self); let ctx = self.breakables.pop().expect("breakable stack broken"); - (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete(self)) } else { None }, res) + (if ctx.may_break { ctx.coerce.map(|ctx| ctx.complete()) } else { None }, res) } } diff --git a/crates/hir-ty/src/infer/mutability.rs b/crates/hir-ty/src/infer/mutability.rs index ac450c0b5591..5f63667faa5b 100644 --- a/crates/hir-ty/src/infer/mutability.rs +++ b/crates/hir-ty/src/infer/mutability.rs @@ -14,7 +14,7 @@ use intern::sym; use crate::{ Adjust, Adjustment, AutoBorrow, Interner, OverloadedDeref, TyBuilder, TyKind, - infer::{Expectation, InferenceContext, expr::ExprIsRead}, + infer::{Expectation, InferenceContext, Resolution, expr::ExprIsRead}, lower::lower_to_chalk_mutability, }; @@ -24,7 +24,7 @@ impl InferenceContext<'_> { } fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { - if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) { + if let Some(adjustments) = self.result.adjustments.get_mut(&tgt_expr.into()) { for adj in adjustments.iter_mut().rev() { match &mut adj.kind { Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (), @@ -125,7 +125,9 @@ impl InferenceContext<'_> { } &Expr::Index { base, index } => { if mutability == Mutability::Mut { - if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if let Some(Resolution::Method(f, _)) = + self.result.resolution.get_mut(&tgt_expr.into()) + { if let Some(index_trait) = LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) { @@ -138,8 +140,8 @@ impl InferenceContext<'_> { let mut base_ty = None; let base_adjustments = self .result - .expr_adjustments - .get_mut(&base) + .adjustments + .get_mut(&base.into()) .and_then(|it| it.last_mut()); if let Some(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)), @@ -179,7 +181,9 @@ impl InferenceContext<'_> { } Expr::UnaryOp { expr, op: UnaryOp::Deref } => { let mut mutability = mutability; - if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { + if let Some(Resolution::Method(f, _)) = + self.result.resolution.get_mut(&tgt_expr.into()) + { if mutability == Mutability::Mut { if let Some(deref_trait) = LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate) diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs index a9a3265858e4..a6e838a50526 100644 --- a/crates/hir-ty/src/infer/pat.rs +++ b/crates/hir-ty/src/infer/pat.rs @@ -11,11 +11,11 @@ use hir_expand::name::Name; use stdx::TupleExt; use crate::{ - DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty, - TyBuilder, TyExt, TyKind, + Adjust, Adjustment, DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar, + Substitution, Ty, TyBuilder, TyExt, TyKind, consteval::{self, try_const_usize, usize_const}, infer::{ - BindingMode, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, + BindingMode, ERROR_TY, Expectation, InferenceContext, TypeMismatch, coerce::CoerceNever, expr::ExprIsRead, }, lower::lower_to_chalk_mutability, @@ -250,7 +250,8 @@ impl InferenceContext<'_> { } else if self.is_non_ref_pat(self.body, pat) { let mut pat_adjustments = Vec::new(); while let Some((inner, _lifetime, mutability)) = expected.as_reference() { - pat_adjustments.push(expected.clone()); + pat_adjustments + .push(Adjustment { kind: Adjust::Deref(None), target: expected.clone() }); expected = self.resolve_ty_shallow(inner); default_bm = match default_bm { BindingMode::Move => BindingMode::Ref(mutability), @@ -260,8 +261,7 @@ impl InferenceContext<'_> { } if !pat_adjustments.is_empty() { - pat_adjustments.shrink_to_fit(); - self.result.pat_adjustments.insert(pat, pat_adjustments); + self.result.adjustments.insert(pat.into(), pat_adjustments.into_boxed_slice()); } } @@ -306,12 +306,13 @@ impl InferenceContext<'_> { match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) { Ok((adjustments, coerced_ty)) => { if !adjustments.is_empty() { - self.result - .pat_adjustments - .entry(pat) - .or_default() - .extend(adjustments.into_iter().map(|adjust| adjust.target)); + let adjustments = match self.result.adjustments.remove(&pat.into()) { + Some(prev) => prev.into_iter().chain(adjustments).collect(), + None => adjustments.into_boxed_slice(), + }; + self.result.adjustments.insert(pat.into(), adjustments); } + self.write_pat_ty(pat, coerced_ty); return self.pat_ty_after_adjustment(pat); } @@ -354,7 +355,7 @@ impl InferenceContext<'_> { subst.at(Interner, 0).assert_ty_ref(Interner).clone(), subst.as_slice(Interner).get(1).and_then(|a| a.ty(Interner).cloned()), ), - _ => (self.result.standard_types.unknown.clone(), None), + _ => (ERROR_TY.clone(), None), }; let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm, decl); @@ -419,10 +420,10 @@ impl InferenceContext<'_> { fn pat_ty_after_adjustment(&self, pat: PatId) -> Ty { self.result - .pat_adjustments - .get(&pat) + .adjustments + .get(&pat.into()) .and_then(|it| it.first()) - .unwrap_or(&self.result.type_of_pat[pat]) + .map_or_else(|| &self.result.type_of_pat[pat], |adj| &adj.target) .clone() } diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 9d4bbe53464d..a40bd807fa3f 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -15,7 +15,7 @@ use crate::{ builder::ParamKind, consteval, error_lifetime, generics::generics, - infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, + infer::{ERROR_TY, diagnostics::InferenceTyLoweringContext as TyLoweringContext}, lower::LifetimeElisionKind, method_resolution::{self, VisibleFromModule}, to_chalk_trait_id, @@ -114,9 +114,7 @@ impl InferenceContext<'_> { let substs = builder .fill(|x| { it.next().unwrap_or_else(|| match x { - ParamKind::Type => { - self.result.standard_types.unknown.clone().cast(Interner) - } + ParamKind::Type => ERROR_TY.clone().cast(Interner), ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), ParamKind::Lifetime => error_lifetime().cast(Interner), }) @@ -138,7 +136,7 @@ impl InferenceContext<'_> { let substs = builder .fill(|x| { it.next().unwrap_or_else(|| match x { - ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner), + ParamKind::Type => ERROR_TY.clone().cast(Interner), ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()), ParamKind::Lifetime => error_lifetime().cast(Interner), }) diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index e6caf2d8d97a..9c45b8648561 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -399,7 +399,7 @@ impl<'ctx> MirLowerCtx<'ctx> { place: Place, prev_block: BasicBlockId, ) -> Result> { - if let Some(adjustments) = self.infer.expr_adjustments.get(&expr_id) { + if let adjustments @ [_, ..] = self.infer.expr_adjustments(expr_id) { return self.lower_expr_to_place_with_adjust(expr_id, place, prev_block, adjustments); } self.lower_expr_to_place_without_adjust(expr_id, place, prev_block) @@ -1054,13 +1054,10 @@ impl<'ctx> MirLowerCtx<'ctx> { } if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op { // last adjustment is `&mut` which we don't want it. - let adjusts = self - .infer - .expr_adjustments - .get(lhs) - .and_then(|it| it.split_last()) - .map(|it| it.1) - .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?; + let adjusts = + self.infer.expr_adjustments(*lhs).split_last().map(|it| it.1).ok_or( + MirLowerError::TypeError("adjustment of binary op was missing"), + )?; let Some((lhs_place, current)) = self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)? else { @@ -1597,10 +1594,8 @@ impl<'ctx> MirLowerCtx<'ctx> { fn expr_ty_after_adjustments(&self, e: ExprId) -> Ty { let mut ty = None; - if let Some(it) = self.infer.expr_adjustments.get(&e) { - if let Some(it) = it.last() { - ty = Some(it.target.clone()); - } + if let Some(it) = self.infer.expr_adjustments(e).last() { + ty = Some(it.target.clone()); } ty.unwrap_or_else(|| self.expr_ty_without_adjust(e)) } @@ -1674,7 +1669,7 @@ impl<'ctx> MirLowerCtx<'ctx> { } fn has_adjustments(&self, expr_id: ExprId) -> bool { - !self.infer.expr_adjustments.get(&expr_id).map(|it| it.is_empty()).unwrap_or(true) + !self.infer.expr_adjustments(expr_id).is_empty() } fn merge_blocks( diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index c22bada7a903..0c5f47d40d01 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -115,9 +115,11 @@ impl MirLowerCtx<'_> { expr_id: ExprId, upgrade_rvalue: bool, ) -> Result> { - match self.infer.expr_adjustments.get(&expr_id) { - Some(a) => self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a), - None => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue), + match self.infer.expr_adjustments(expr_id) { + a @ [_, ..] => { + self.lower_expr_as_place_with_adjust(current, expr_id, upgrade_rvalue, a) + } + [] => self.lower_expr_as_place_without_adjust(current, expr_id, upgrade_rvalue), } } @@ -254,13 +256,8 @@ impl MirLowerCtx<'_> { index_fn, ); } - let adjusts = self - .infer - .expr_adjustments - .get(base) - .and_then(|it| it.split_last()) - .map(|it| it.1) - .unwrap_or(&[]); + let adjusts = + self.infer.expr_adjustments(*base).split_last().map(|it| it.1).unwrap_or(&[]); let Some((mut p_base, current)) = self.lower_expr_as_place_with_adjust(current, *base, true, adjusts)? else { diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index b3c1f6f387f2..8ddff94275e1 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -119,7 +119,7 @@ impl MirLowerCtx<'_> { pattern: PatId, mode: MatchingMode, ) -> Result<(BasicBlockId, Option)> { - let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default(); + let cnt = self.infer.pat_adjustments(pattern).len(); cond_place.projection = self.result.projection_store.intern( cond_place .projection diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2b75bd6f1604..cb14e6956850 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -201,10 +201,7 @@ fn check_impl( assert_eq!(actual, expected, "type annotation differs at {:#?}", range.range); } if let Some(expected) = adjustments.remove(&range) { - let adjustments = inference_result - .expr_adjustments - .get(&expr) - .map_or_else(Default::default, |it| &**it); + let adjustments = inference_result.expr_adjustments(expr); assert_eq!( expected, adjustments diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index d22812d3c692..c507ce233364 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -254,7 +254,8 @@ impl<'db> SourceAnalyzer<'db> { // expressions nor patterns). let expr_id = self.expr_id(expr.clone())?.as_expr()?; let infer = self.infer()?; - infer.expr_adjustments.get(&expr_id).map(|v| &**v) + let adjustment = infer.expr_adjustments(expr_id); + if adjustment.is_empty() { None } else { Some(adjustment) } } pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option { @@ -282,7 +283,7 @@ impl<'db> SourceAnalyzer<'db> { let infer = self.infer()?; let coerced = expr_id .as_expr() - .and_then(|expr_id| infer.expr_adjustments.get(&expr_id)) + .map(|expr_id| infer.expr_adjustments(expr_id)) .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone())); let ty = infer[expr_id].clone(); let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); @@ -297,15 +298,12 @@ impl<'db> SourceAnalyzer<'db> { let expr_or_pat_id = self.pat_id(pat)?; let infer = self.infer()?; let coerced = match expr_or_pat_id { - ExprOrPatId::ExprId(idx) => infer - .expr_adjustments - .get(&idx) - .and_then(|adjusts| adjusts.last().cloned()) - .map(|adjust| adjust.target), - ExprOrPatId::PatId(idx) => { - infer.pat_adjustments.get(&idx).and_then(|adjusts| adjusts.last().cloned()) - } - }; + ExprOrPatId::ExprId(idx) => infer.expr_adjustments(idx), + ExprOrPatId::PatId(idx) => infer.pat_adjustments(idx), + } + .last() + .cloned() + .map(|adjust| adjust.target); let ty = infer[expr_or_pat_id].clone(); let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty); @@ -356,14 +354,12 @@ impl<'db> SourceAnalyzer<'db> { ) -> Option> { let pat_id = self.pat_id(pat)?; let infer = self.infer()?; - Some( - infer - .pat_adjustments - .get(&pat_id.as_pat()?)? - .iter() - .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone())) - .collect(), - ) + let collect: SmallVec<_> = infer + .pat_adjustments(pat_id.as_pat()?) + .iter() + .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.target.clone())) + .collect(); + if collect.is_empty() { None } else { Some(collect) } } pub(crate) fn resolve_method_call_as_callable( @@ -1780,7 +1776,7 @@ pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> H } fn type_of_expr_including_adjust(infer: &InferenceResult, id: ExprId) -> Option<&Ty> { - match infer.expr_adjustments.get(&id).and_then(|adjustments| adjustments.last()) { + match infer.expr_adjustments(id).last() { Some(adjustment) => Some(&adjustment.target), None => infer.type_of_expr.get(id), }