diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs index 66eade224575..53be0de7d9c3 100644 --- a/crates/hir-def/src/hir.rs +++ b/crates/hir-def/src/hir.rs @@ -45,7 +45,7 @@ pub type PatId = Idx; // FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts // are local to the body. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, salsa::Update)] pub enum ExprOrPatId { ExprId(ExprId), PatId(PatId), diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index eceadd6742ab..ad247e0d6897 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -600,17 +600,17 @@ impl HasModule for ModuleId { /// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] pub struct FieldId { // FIXME: Store this as an erased `salsa::Id` to save space pub parent: VariantId, pub local_id: LocalFieldId, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] pub struct TupleId(pub u32); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] pub struct TupleFieldId { pub tuple: TupleId, pub index: u32, @@ -1014,7 +1014,7 @@ impl From for AttrDefId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype, salsa::Update)] pub enum VariantId { EnumVariantId(EnumVariantId), StructId(StructId), diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index 40e58aaa9e0a..df058711a685 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -12,7 +12,7 @@ use salsa::plumbing::AsId; use triomphe::Arc; use crate::{ - ImplTraitId, InferenceResult, TraitEnvironment, TyDefId, ValueTyDefId, + ImplTraitId, TraitEnvironment, TyDefId, ValueTyDefId, consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, @@ -23,10 +23,6 @@ use crate::{ #[query_group::query_group] pub trait HirDatabase: DefDatabase + std::fmt::Debug { - #[salsa::invoke(crate::infer::infer_query)] - #[salsa::cycle(cycle_result = crate::infer::infer_cycle_result)] - fn infer<'db>(&'db self, def: DefWithBodyId) -> Arc>; - // region:mir // FXME: Collapse `mir_body_for_closure` into `mir_body` diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index b84b70c197d0..719c7daf425e 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -76,7 +76,7 @@ impl BodyValidationDiagnostic { validate_lints: bool, ) -> Vec { let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let body = db.body(owner); let env = db.trait_environment_for_body(owner); let interner = DbInterner::new_with(db, env.krate, env.block); @@ -99,7 +99,7 @@ impl BodyValidationDiagnostic { struct ExprValidator<'db> { owner: DefWithBodyId, body: Arc, - infer: Arc>, + infer: &'db InferenceResult<'db>, env: Arc>, diagnostics: Vec, validate_lints: bool, @@ -124,7 +124,7 @@ impl<'db> ExprValidator<'db> { for (id, expr) in body.exprs() { if let Some((variant, missed_fields, true)) = - record_literal_missing_fields(db, &self.infer, id, expr) + record_literal_missing_fields(db, self.infer, id, expr) { self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { record: Either::Left(id), @@ -155,7 +155,7 @@ impl<'db> ExprValidator<'db> { for (id, pat) in body.pats() { if let Some((variant, missed_fields, true)) = - record_pattern_missing_fields(db, &self.infer, id, pat) + record_pattern_missing_fields(db, self.infer, id, pat) { self.diagnostics.push(BodyValidationDiagnostic::RecordMissingFields { record: Either::Right(id), @@ -240,7 +240,7 @@ impl<'db> ExprValidator<'db> { .as_reference() .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) .unwrap_or(false)) - && types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer) + && types_of_subpatterns_do_match(arm.pat, &self.body, self.infer) { // If we had a NotUsefulMatchArm diagnostic, we could // check the usefulness of each pattern as we added it @@ -388,7 +388,7 @@ impl<'db> ExprValidator<'db> { pat: PatId, have_errors: &mut bool, ) -> DeconstructedPat<'a, 'db> { - let mut patcx = match_check::PatCtxt::new(self.db(), &self.infer, &self.body); + let mut patcx = match_check::PatCtxt::new(self.db(), self.infer, &self.body); let pattern = patcx.lower_pattern(pat); let pattern = cx.lower_pat(&pattern); if !patcx.errors.is_empty() { diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs index 8ac7ab19cd3b..6160962e3bb7 100644 --- a/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -42,7 +42,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe let mut res = MissingUnsafeResult { fn_is_unsafe: is_unsafe, ..MissingUnsafeResult::default() }; let body = db.body(def); - let infer = db.infer(def); + let infer = InferenceResult::for_body(db, def); let mut callback = |diag| match diag { UnsafeDiagnostic::UnsafeOperation { node, inside_unsafe_block, reason } => { if inside_unsafe_block == InsideUnsafeBlock::No { @@ -55,7 +55,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafe } } }; - let mut visitor = UnsafeVisitor::new(db, &infer, &body, def, &mut callback); + let mut visitor = UnsafeVisitor::new(db, infer, &body, def, &mut callback); visitor.walk_expr(body.body_expr); if !is_unsafe { diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 2c6d7c68d1d3..3bb8be02aaf7 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -47,7 +47,7 @@ use stdx::never; use triomphe::Arc; use crate::{ - CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval, + CallableDefId, FnAbi, ImplTraitId, InferenceResult, MemoryMap, TraitEnvironment, consteval, db::{HirDatabase, InternedClosure, InternedCoroutine}, generics::generics, layout::Layout, @@ -1398,7 +1398,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { if let Some(sig) = sig { let sig = sig.skip_binder(); let InternedClosure(def, _) = db.lookup_intern_closure(id); - let infer = db.infer(def); + let infer = InferenceResult::for_body(db, def); let (_, kind) = infer.closure_info(id); match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?, diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs index 124e7b279f13..d76de4b8ca11 100644 --- a/crates/hir-ty/src/drop.rs +++ b/crates/hir-ty/src/drop.rs @@ -7,7 +7,7 @@ use stdx::never; use triomphe::Arc; use crate::{ - TraitEnvironment, consteval, + InferenceResult, TraitEnvironment, consteval, method_resolution::TraitImpls, next_solver::{ DbInterner, SimplifiedType, Ty, TyKind, @@ -137,7 +137,7 @@ fn has_drop_glue_impl<'db>( TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited), TyKind::Closure(closure_id, subst) => { let owner = db.lookup_intern_closure(closure_id.0).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let (captures, _) = infer.closure_info(closure_id.0); let env = db.trait_environment_for_body(owner); captures diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 36b7015817fe..ab173799bc10 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -54,10 +54,10 @@ use rustc_type_ir::{ AliasTyKind, TypeFoldable, inherent::{AdtDef, IntoKind, Region as _, SliceLike, Ty as _}, }; +use salsa::Update; use span::Edition; use stdx::never; use thin_vec::ThinVec; -use triomphe::Arc; use crate::{ ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, TargetFeatures, @@ -95,7 +95,7 @@ use cast::{CastCheck, CastError}; pub(crate) use closure::analysis::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. -pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc> { +fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'_> { let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = db.body(def); @@ -159,17 +159,14 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc Arc> { - Arc::new(InferenceResult { +fn infer_cycle_result(db: &dyn HirDatabase, _: DefWithBodyId) -> InferenceResult<'_> { + InferenceResult { has_errors: true, ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed)) - }) + } } /// Binding modes inferred for patterns. @@ -199,7 +196,7 @@ pub enum InferenceTyDiagnosticSource { Signature, } -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Update)] pub enum InferenceDiagnostic<'db> { NoSuchField { field: ExprOrPatId, @@ -293,7 +290,7 @@ pub enum InferenceDiagnostic<'db> { } /// A mismatch between an expected and an inferred type. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash, Update)] pub struct TypeMismatch<'db> { pub expected: Ty<'db>, pub actual: Ty<'db>, @@ -339,7 +336,7 @@ pub struct TypeMismatch<'db> { /// At some point, of course, `Box` should move out of the compiler, in which /// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> /// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. -#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, Update)] pub struct Adjustment<'db> { #[type_visitable(ignore)] #[type_foldable(identity)] @@ -476,9 +473,10 @@ pub enum PointerCast { /// When you add a field that stores types (including `Substitution` and the like), don't forget /// `resolve_completely()`'ing them in `InferenceContext::resolve_all()`. Inference variables must /// not appear in the final inference result. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Update)] pub struct InferenceResult<'db> { /// For each method call expr, records the function it resolves to. + #[update(unsafe(with(crate::utils::unsafe_update_eq /* expr id is technically update */)))] method_resolutions: FxHashMap)>, /// For each field access expr, records the field it resolves to. field_resolutions: FxHashMap>, @@ -489,15 +487,20 @@ pub struct InferenceResult<'db> { /// 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. - tuple_field_access_types: FxHashMap>, + #[update(unsafe(with(crate::utils::unsafe_update_eq /* thinvec is technically update */)))] + tuple_field_access_types: ThinVec>, + #[update(unsafe(with(crate::utils::unsafe_update_eq /* expr id is technically update */)))] pub(crate) type_of_expr: ArenaMap>, /// 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. + #[update(unsafe(with(crate::utils::unsafe_update_eq /* pat id is technically update */)))] pub(crate) type_of_pat: ArenaMap>, + #[update(unsafe(with(crate::utils::unsafe_update_eq /* binding id is technically update */)))] pub(crate) type_of_binding: ArenaMap>, + #[update(unsafe(with(crate::utils::unsafe_update_eq /* type ref id is technically update */)))] pub(crate) type_of_type_placeholder: FxHashMap>, pub(crate) type_of_opaque: FxHashMap>, @@ -508,14 +511,17 @@ pub struct InferenceResult<'db> { // Which will then mark this field. pub(crate) has_errors: bool, /// During inference this field is empty and [`InferenceContext::diagnostics`] is filled instead. + #[update(unsafe(with(crate::utils::unsafe_update_eq /* thinvec is technically update */)))] diagnostics: ThinVec>, /// Interned `Error` type to return references to. // FIXME: Remove this. error_ty: Ty<'db>, + #[update(unsafe(with(crate::utils::unsafe_update_eq /* expr id is technically update */)))] pub(crate) expr_adjustments: FxHashMap]>>, /// Stores the types which were implicitly dereferenced in pattern binding modes. + #[update(unsafe(with(crate::utils::unsafe_update_eq /* pat id is technically update */)))] pub(crate) pat_adjustments: FxHashMap>>, /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings. /// @@ -539,6 +545,14 @@ pub struct InferenceResult<'db> { pub(crate) coercion_casts: FxHashSet, } +#[salsa::tracked] +impl<'db> InferenceResult<'db> { + #[salsa::tracked(returns(ref), cycle_result = infer_cycle_result)] + pub fn for_body(db: &'db dyn HirDatabase, def: DefWithBodyId) -> InferenceResult<'db> { + infer_query(db, def) + } +} + impl<'db> InferenceResult<'db> { fn new(error_ty: Ty<'db>) -> Self { Self { @@ -672,7 +686,7 @@ impl<'db> InferenceResult<'db> { } pub fn tuple_field_access_type(&self, id: TupleId) -> Tys<'db> { - self.tuple_field_access_types[&id] + self.tuple_field_access_types[id.0 as usize] } pub fn pat_adjustment(&self, id: PatId) -> Option<&[Ty<'db>]> { @@ -1135,9 +1149,8 @@ impl<'body, 'db> InferenceContext<'body, 'db> { pat_adjustments.shrink_to_fit(); result.tuple_field_access_types = tuple_field_accesses_rev .into_iter() - .enumerate() - .map(|(idx, subst)| (TupleId(idx as u32), table.resolve_completely(subst))) - .inspect(|(_, subst)| { + .map(|subst| table.resolve_completely(subst)) + .inspect(|subst| { *has_errors = *has_errors || subst.iter().any(|ty| ty.references_non_lt_error()); }) .collect(); diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index 935c5a507849..251e7f7cf6b8 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -31,10 +31,10 @@ use crate::{ // The below functions handle capture and closure kind (Fn, FnMut, ..) -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, salsa::Update)] pub(crate) struct HirPlace<'db> { pub(crate) local: BindingId, - pub(crate) projections: Vec>>, + pub(crate) projections: Vec>, } impl<'db> HirPlace<'db> { @@ -76,7 +76,7 @@ pub enum CaptureKind { ByValue, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, salsa::Update)] pub struct CapturedItem<'db> { pub(crate) place: HirPlace<'db>, pub(crate) kind: CaptureKind, @@ -87,6 +87,7 @@ pub struct CapturedItem<'db> { /// copy all captures of the inner closure to the outer closure, and then we may /// truncate them, and we want the correct span to be reported. span_stacks: SmallVec<[SmallVec<[MirSpan; 3]>; 3]>, + #[update(unsafe(with(crate::utils::unsafe_update_eq)))] pub(crate) ty: EarlyBinder<'db, Ty<'db>>, } diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index 658172d4b086..0a6bb4900f94 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -21,7 +21,7 @@ use rustc_type_ir::{ use triomphe::Arc; use crate::{ - TraitEnvironment, + InferenceResult, TraitEnvironment, consteval::try_const_usize, db::HirDatabase, next_solver::{ @@ -322,7 +322,7 @@ pub fn layout_of_ty_query<'db>( } TyKind::Closure(id, args) => { let def = db.lookup_intern_closure(id.0); - let infer = db.infer(def.0); + let infer = InferenceResult::for_body(db, def.0); let (captures, _) = infer.closure_info(id.0); let fields = captures .iter() diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 2ce0a6792099..878813a69651 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -9,6 +9,7 @@ use test_fixture::WithFixture; use triomphe::Arc; use crate::{ + InferenceResult, db::HirDatabase, layout::{Layout, LayoutError}, next_solver::{DbInterner, GenericArgs}, @@ -136,7 +137,7 @@ fn eval_expr( .find(|x| x.1.name.display_no_db(file_id.edition(&db)).to_smolstr() == "goal") .unwrap() .0; - let infer = db.infer(function_id.into()); + let infer = InferenceResult::for_body(&db, function_id.into()); let goal_ty = infer.type_of_binding[b]; db.layout_of_ty(goal_ty, db.trait_environment(function_id.into())) }) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 8da6baba5dc8..c104ab6a78a4 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -81,7 +81,7 @@ pub struct MethodResolutionContext<'a, 'db> { pub unstable_features: &'a MethodResolutionUnstableFeatures, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Update)] pub enum CandidateId { FunctionId(FunctionId), ConstId(ConstId), diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 317578fcd9fd..f47e3b7a3089 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -140,21 +140,21 @@ impl<'db> Operand<'db> { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ProjectionElem { +#[derive(Debug, Clone, PartialEq, Eq, Hash, salsa::Update)] +pub enum ProjectionElem<'db, V: PartialEq> { Deref, Field(Either), // FIXME: get rid of this, and use FieldId for tuples and closures ClosureField(usize), - Index(V), + Index(#[update(unsafe(with(crate::utils::unsafe_update_eq)))] V), ConstantIndex { offset: u64, from_end: bool }, Subslice { from: u64, to: u64 }, //Downcast(Option, VariantIdx), - OpaqueCast(T), + OpaqueCast(Ty<'db>), } -impl ProjectionElem { - pub fn projected_ty<'db>( +impl<'db, V: PartialEq> ProjectionElem<'db, V> { + pub fn projected_ty( &self, infcx: &InferCtxt<'db>, mut base: Ty<'db>, @@ -254,7 +254,7 @@ impl ProjectionElem { } } -type PlaceElem<'db> = ProjectionElem, Ty<'db>>; +type PlaceElem<'db> = ProjectionElem<'db, LocalId<'db>>; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProjectionId(u32); diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index acd064598a42..12a08397fd09 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -12,7 +12,7 @@ use stdx::never; use triomphe::Arc; use crate::{ - TraitEnvironment, + InferenceResult, TraitEnvironment, db::{HirDatabase, InternedClosure, InternedClosureId}, display::DisplayTarget, mir::OperandKind, @@ -121,7 +121,7 @@ fn make_fetch_closure_field<'db>( ) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> { |c: InternedClosureId, subst: GenericArgs<'db>, f: usize| { let InternedClosure(def, _) = db.lookup_intern_closure(c); - let infer = db.infer(def); + let infer = InferenceResult::for_body(db, def); let (captures, _) = infer.closure_info(c); let parent_subst = subst.split_closure_args_untupled().parent_args; let interner = DbInterner::new_no_crate(db); diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 7e3a120c06a3..68c9fb851d3c 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -34,7 +34,7 @@ use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{ - CallableDefId, ComplexMemoryMap, MemoryMap, TraitEnvironment, + CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, TraitEnvironment, consteval::{self, ConstEvalError, try_const_usize}, db::{HirDatabase, InternedClosure, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, @@ -722,7 +722,7 @@ impl<'db> Evaluator<'db> { ty, |c, subst, f| { let InternedClosure(def, _) = self.db.lookup_intern_closure(c); - let infer = self.db.infer(def); + let infer = InferenceResult::for_body(self.db, def); let (captures, _) = infer.closure_info(c); let parent_subst = subst.split_closure_args_untupled().parent_args; captures @@ -883,7 +883,8 @@ impl<'db> Evaluator<'db> { OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, OperandKind::Constant { konst: _, ty } => *ty, &OperandKind::Static(s) => { - let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr]; + let ty = + InferenceResult::for_body(self.db, s.into())[self.db.body(s.into()).body_expr]; Ty::new_ref( self.interner(), Region::new_static(self.interner()), @@ -2809,7 +2810,8 @@ impl<'db> Evaluator<'db> { })?; self.allocate_const_in_heap(locals, konst)? } else { - let ty = self.db.infer(st.into())[self.db.body(st.into()).body_expr]; + let ty = + InferenceResult::for_body(self.db, st.into())[self.db.body(st.into()).body_expr]; let Some((size, align)) = self.size_align_of(ty, locals)? else { not_supported!("unsized extern static"); }; diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs index cf08c82408c6..591c12ec24c7 100644 --- a/crates/hir-ty/src/mir/eval/shim.rs +++ b/crates/hir-ty/src/mir/eval/shim.rs @@ -10,6 +10,7 @@ use rustc_type_ir::inherent::{AdtDef, IntoKind, SliceLike, Ty as _}; use stdx::never; use crate::{ + InferenceResult, display::DisplayTarget, drop::{DropGlue, has_drop_glue}, mir::eval::{ @@ -167,7 +168,7 @@ impl<'db> Evaluator<'db> { }; let addr = Address::from_bytes(arg.get(self)?)?; let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0); - let infer = self.db.infer(closure_owner); + let infer = InferenceResult::for_body(self.db, closure_owner); let (captures, _) = infer.closure_info(id.0); let layout = self.layout(self_ty)?; let db = self.db; diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index be2291a62c9c..5454e8b753be 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2111,7 +2111,7 @@ pub fn mir_body_for_closure_query<'db>( ) -> Result<'db, Arc>> { let InternedClosure(owner, expr) = db.lookup_intern_closure(closure); let body = db.body(owner); - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let Expr::Closure { args, body: root, .. } = &body[expr] else { implementation_error!("closure expression is not closure"); }; @@ -2119,7 +2119,7 @@ pub fn mir_body_for_closure_query<'db>( implementation_error!("closure expression is not closure"); }; let (captures, kind) = infer.closure_info(closure); - let mut ctx = MirLowerCtx::new(db, owner, &body, &infer); + let mut ctx = MirLowerCtx::new(db, owner, &body, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: infer[*root] }); let closure_local = ctx.result.locals.alloc(Local { @@ -2249,8 +2249,8 @@ pub fn mir_body_query<'db>( }; let _p = tracing::info_span!("mir_body_query", ?detail).entered(); let body = db.body(def); - let infer = db.infer(def); - let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; + let infer = InferenceResult::for_body(db, def); + let mut result = lower_to_mir(db, def, &body, infer, body.body_expr)?; result.shrink_to_fit(); Ok(Arc::new(result)) } diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index fa99013d5e95..3a3e0040e519 100644 --- a/crates/hir-ty/src/opaques.rs +++ b/crates/hir-ty/src/opaques.rs @@ -9,7 +9,7 @@ use rustc_type_ir::inherent::Ty as _; use syntax::ast; use crate::{ - ImplTraitId, + ImplTraitId, InferenceResult, db::{HirDatabase, InternedOpaqueTyId}, lower::{ImplTraitIdx, ImplTraits}, next_solver::{ @@ -94,7 +94,7 @@ pub(crate) fn rpit_hidden_types<'db>( db: &'db dyn HirDatabase, function: FunctionId, ) -> ArenaMap, EarlyBinder<'db, Ty<'db>>> { - let infer = db.infer(function.into()); + let infer = InferenceResult::for_body(db, function.into()); let mut result = ArenaMap::new(); for (opaque, hidden_type) in infer.return_position_impl_trait_types(db) { result.insert(opaque, EarlyBinder::bind(hidden_type)); @@ -128,7 +128,7 @@ pub(crate) fn tait_hidden_types<'db>( let mut result = ArenaMap::with_capacity(taits_count); for defining_body in defining_bodies { - let infer = db.infer(defining_body); + let infer = InferenceResult::for_body(db, defining_body); for (&opaque, &hidden_type) in &infer.type_of_opaque { let ImplTraitId::TypeAliasImplTrait(opaque_owner, opaque_idx) = opaque.loc(db) else { continue; diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 002d58961d22..1acb0b82b146 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -38,7 +38,6 @@ use triomphe::Arc; use crate::{ InferenceResult, - db::HirDatabase, display::{DisplayTarget, HirDisplay}, infer::{Adjustment, TypeMismatch}, next_solver::Ty, @@ -148,7 +147,7 @@ fn check_impl( for (def, krate) in defs { let display_target = DisplayTarget::from_crate(&db, krate); let (body, body_source_map) = db.body_with_source_map(def); - let inference_result = db.infer(def); + let inference_result = InferenceResult::for_body(&db, def); for (pat, mut ty) in inference_result.type_of_pat.iter() { if let Pat::Bind { id, .. } = body[pat] { @@ -319,7 +318,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { crate::attach_db(&db, || { let mut buf = String::new(); - let mut infer_def = |inference_result: Arc>, + let mut infer_def = |inference_result: &InferenceResult<'_>, body: Arc, body_source_map: Arc, krate: Crate| { @@ -443,7 +442,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { }); for (def, krate) in defs { let (body, source_map) = db.body_with_source_map(def); - let infer = db.infer(def); + let infer = InferenceResult::for_body(&db, def); infer_def(infer, body, source_map, krate); } @@ -595,13 +594,16 @@ fn salsa_bug() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { - db.infer(match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }); + InferenceResult::for_body( + &db, + match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }, + ); }); }); @@ -636,13 +638,16 @@ fn salsa_bug() { let module = db.module_for_file(pos.file_id.file_id(&db)); let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { - db.infer(match def { - ModuleDefId::FunctionId(it) => it.into(), - ModuleDefId::EnumVariantId(it) => it.into(), - ModuleDefId::ConstId(it) => it.into(), - ModuleDefId::StaticId(it) => it.into(), - _ => return, - }); + InferenceResult::for_body( + &db, + match def { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::EnumVariantId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => return, + }, + ); }); }) } diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs index 8425c0dd8990..ef71681636ef 100644 --- a/crates/hir-ty/src/tests/closure_captures.rs +++ b/crates/hir-ty/src/tests/closure_captures.rs @@ -7,6 +7,7 @@ use syntax::{AstNode, AstPtr}; use test_fixture::WithFixture; use crate::{ + InferenceResult, db::HirDatabase, display::{DisplayTarget, HirDisplay}, mir::MirSpan, @@ -34,7 +35,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec hir_def::ModuleDefId::StaticId(it) => it.into(), _ => continue, }; - let infer = db.infer(def); + let infer = InferenceResult::for_body(&db, def); let db = &db; captures_info.extend(infer.closure_info.iter().flat_map( |(closure_id, (captures, _))| { diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 87291b619ae5..fd564a300dce 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -4,7 +4,7 @@ use hir_def::{DefWithBodyId, ModuleDefId}; use salsa::EventKind; use test_fixture::WithFixture; -use crate::{db::HirDatabase, method_resolution::TraitImpls, test_db::TestDB}; +use crate::{InferenceResult, method_resolution::TraitImpls, test_db::TestDB}; use super::visit_module; @@ -24,11 +24,11 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - db.infer(it.into()); + InferenceResult::for_body(&db, it.into()); } }); }, - &[("infer_shim", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ "crate_local_def_map", @@ -36,7 +36,7 @@ fn foo() -> i32 { "ast_id_map_shim", "parse_shim", "real_span_map_shim", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", "AttrFlags::query_", @@ -68,11 +68,11 @@ fn foo() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - db.infer(it.into()); + InferenceResult::for_body(&db, it.into()); } }); }, - &[("infer_shim", 0)], + &[("InferenceResult < 'db >::for_body_", 0)], expect_test::expect![[r#" [ "parse_shim", @@ -111,11 +111,11 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - db.infer(it.into()); + InferenceResult::for_body(&db, it.into()); } }); }, - &[("infer_shim", 3)], + &[("InferenceResult < 'db >::for_body_", 3)], expect_test::expect![[r#" [ "crate_local_def_map", @@ -123,7 +123,7 @@ fn baz() -> i32 { "ast_id_map_shim", "parse_shim", "real_span_map_shim", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", "AttrFlags::query_", @@ -137,7 +137,7 @@ fn baz() -> i32 { "GenericPredicates < 'db >::query_with_diagnostics_", "ImplTraits < 'db >::return_type_impl_traits_", "expr_scopes_shim", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", "body_shim", @@ -146,7 +146,7 @@ fn baz() -> i32 { "GenericPredicates < 'db >::query_with_diagnostics_", "ImplTraits < 'db >::return_type_impl_traits_", "expr_scopes_shim", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", "body_shim", @@ -180,11 +180,11 @@ fn baz() -> i32 { let crate_def_map = module.def_map(&db); visit_module(&db, crate_def_map, module.local_id, &mut |def| { if let ModuleDefId::FunctionId(it) = def { - db.infer(it.into()); + InferenceResult::for_body(&db, it.into()); } }); }, - &[("infer_shim", 1)], + &[("InferenceResult < 'db >::for_body_", 1)], expect_test::expect![[r#" [ "parse_shim", @@ -202,7 +202,7 @@ fn baz() -> i32 { "function_signature_shim", "body_with_source_map_shim", "body_shim", - "infer_shim", + "InferenceResult < 'db >::for_body_", "expr_scopes_shim", "function_signature_with_source_map_shim", "function_signature_shim", @@ -558,7 +558,7 @@ fn main() { }); for def in defs { - let _inference_result = db.infer(def); + let _inference_result = InferenceResult::for_body(&db, def); } }, &[("trait_solve_shim", 0)], @@ -574,7 +574,7 @@ fn main() { "body_with_source_map_shim", "AttrFlags::query_", "ImplItems::of_", - "infer_shim", + "InferenceResult < 'db >::for_body_", "trait_signature_shim", "trait_signature_with_source_map_shim", "AttrFlags::query_", @@ -591,7 +591,7 @@ fn main() { "GenericPredicates < 'db >::query_with_diagnostics_", "GenericPredicates < 'db >::query_with_diagnostics_", "ImplTraits < 'db >::return_type_impl_traits_", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_shim", "function_signature_with_source_map_shim", "trait_environment_shim", @@ -655,7 +655,7 @@ fn main() { }); for def in defs { - let _inference_result = db.infer(def); + let _inference_result = InferenceResult::for_body(&db, def); } }, &[("trait_solve_shim", 0)], @@ -671,7 +671,7 @@ fn main() { "AttrFlags::query_", "body_shim", "ImplItems::of_", - "infer_shim", + "InferenceResult < 'db >::for_body_", "AttrFlags::query_", "trait_signature_with_source_map_shim", "AttrFlags::query_", @@ -686,7 +686,7 @@ fn main() { "GenericPredicates < 'db >::query_with_diagnostics_", "GenericPredicates < 'db >::query_with_diagnostics_", "ImplTraits < 'db >::return_type_impl_traits_", - "infer_shim", + "InferenceResult < 'db >::for_body_", "function_signature_with_source_map_shim", "GenericPredicates < 'db >::query_with_diagnostics_", "ImplTraits < 'db >::return_type_impl_traits_", diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 386a95eeb797..bd723ef0c438 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -151,7 +151,7 @@ pub fn next_trait_solve_in_ctxt<'db, 'a>( res } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Update)] pub enum FnTrait { // Warning: Order is important. If something implements `x` it should also implement // `y` if `y <= x`. diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs index efc0ac2bf879..7dd73f1e7aa0 100644 --- a/crates/hir-ty/src/utils.rs +++ b/crates/hir-ty/src/utils.rs @@ -25,6 +25,26 @@ use crate::{ mir::pad16, }; +/// SAFETY: `old_pointer` must be valid for unique writes +pub(crate) unsafe fn unsafe_update_eq(old_pointer: *mut T, new_value: T) -> bool +where + T: PartialEq, +{ + // SAFETY: Caller obligation + let old_ref: &mut T = unsafe { &mut *old_pointer }; + + if *old_ref != new_value { + *old_ref = new_value; + true + } else { + // Subtle but important: Eq impls can be buggy or define equality + // in surprising ways. If it says that the value has not changed, + // we do not modify the existing value, and thus do not have to + // update the revision, as downstream code will not see the new value. + false + } +} + pub(crate) fn fn_traits(lang_items: &LangItems) -> impl Iterator + '_ { [lang_items.Fn, lang_items.FnMut, lang_items.FnOnce].into_iter().flatten() } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index a79dea19490c..40d48d4bbcd5 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -76,8 +76,8 @@ use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind, }; use hir_ty::{ - GenericPredicates, TraitEnvironment, TyDefId, TyLoweringDiagnostic, ValueTyDefId, - all_super_traits, autoderef, check_orphan_rules, + GenericPredicates, InferenceResult, TraitEnvironment, TyDefId, TyLoweringDiagnostic, + ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, db::{InternedClosureId, InternedCoroutineId}, diagnostics::BodyValidationDiagnostic, @@ -1239,8 +1239,7 @@ impl TupleField { pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let interner = DbInterner::new_no_crate(db); - let ty = db - .infer(self.owner) + let ty = InferenceResult::for_body(db, self.owner) .tuple_field_access_type(self.tuple) .as_slice() .get(self.index as usize) @@ -1956,7 +1955,7 @@ impl DefWithBody { expr_store_diagnostics(db, acc, &source_map); - let infer = db.infer(self.into()); + let infer = InferenceResult::for_body(db, self.into()); for d in infer.diagnostics() { acc.extend(AnyDiagnostic::inference_diagnostic( db, @@ -3844,7 +3843,7 @@ impl Local { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; - let infer = db.infer(def); + let infer = InferenceResult::for_body(db, def); let ty = infer[self.binding_id]; Type::new(db, def, ty) } @@ -4540,7 +4539,7 @@ impl<'db> Closure<'db> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let info = infer.closure_info(id); info.0 .iter() @@ -4555,7 +4554,7 @@ impl<'db> Closure<'db> { return Vec::new(); }; let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let (captures, _) = infer.closure_info(id); let env = db.trait_environment_for_body(owner); captures @@ -4568,7 +4567,7 @@ impl<'db> Closure<'db> { match self.id { AnyClosureId::ClosureId(id) => { let owner = db.lookup_intern_closure(id).0; - let infer = db.infer(owner); + let infer = InferenceResult::for_body(db, owner); let info = infer.closure_info(id); info.1.into() } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 3d4859424f9f..82e60bff5e96 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -28,6 +28,7 @@ use hir_expand::{ name::AsName, }; use hir_ty::{ + InferenceResult, diagnostics::{unsafe_operations, unsafe_operations_for_body}, next_solver::DbInterner, }; @@ -1777,9 +1778,9 @@ impl<'db> SemanticsImpl<'db> { pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet { let def = DefWithBodyId::from(def); let (body, source_map) = self.db.body_with_source_map(def); - let infer = self.db.infer(def); + let infer = InferenceResult::for_body(self.db, def); let mut res = FxHashSet::default(); - unsafe_operations_for_body(self.db, &infer, def, &body, &mut |node| { + unsafe_operations_for_body(self.db, infer, def, &body, &mut |node| { if let Ok(node) = source_map.expr_or_pat_syntax(node) { res.insert(node); } @@ -1793,12 +1794,12 @@ impl<'db> SemanticsImpl<'db> { let Some(def) = self.body_for(block.syntax()) else { return Vec::new() }; let def = def.into(); let (body, source_map) = self.db.body_with_source_map(def); - let infer = self.db.infer(def); + let infer = InferenceResult::for_body(self.db, def); let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else { return Vec::new(); }; let mut res = Vec::default(); - unsafe_operations(self.db, &infer, def, &body, block, &mut |node, _| { + unsafe_operations(self.db, infer, def, &body, block, &mut |node, _| { if let Ok(node) = source_map.expr_or_pat_syntax(node) { res.push(node); } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f29e4ccf6070..6def6774e1c8 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -78,7 +78,7 @@ pub(crate) enum BodyOrSig<'db> { def: DefWithBodyId, body: Arc, source_map: Arc, - infer: Option>>, + infer: Option<&'db InferenceResult<'db>>, }, // To be folded into body once it is considered one VariantFields { @@ -101,7 +101,7 @@ impl<'db> SourceAnalyzer<'db> { node: InFile<&SyntaxNode>, offset: Option, ) -> SourceAnalyzer<'db> { - Self::new_for_body_(db, def, node, offset, Some(db.infer(def))) + Self::new_for_body_(db, def, node, offset, Some(InferenceResult::for_body(db, def))) } pub(crate) fn new_for_body_no_infer( @@ -118,7 +118,7 @@ impl<'db> SourceAnalyzer<'db> { def: DefWithBodyId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option, - infer: Option>>, + infer: Option<&'db InferenceResult<'db>>, ) -> SourceAnalyzer<'db> { let (body, source_map) = db.body_with_source_map(def); let scopes = db.expr_scopes(def); diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index ef73b00db4e2..767672fc2fb3 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -20,6 +20,7 @@ use hir_def::{ expr_store::BodySourceMap, hir::{ExprId, PatId}, }; +use hir_ty::InferenceResult; use ide::{ Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RootDatabase, @@ -745,7 +746,7 @@ impl flags::AnalysisStats { .par_iter() .map_with(db.clone(), |snap, &body| { snap.body(body.into()); - snap.infer(body.into()); + InferenceResult::for_body(snap, body.into()); }) .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); @@ -802,7 +803,8 @@ impl flags::AnalysisStats { } bar.set_message(msg); let body = db.body(body_id.into()); - let inference_result = catch_unwind(AssertUnwindSafe(|| db.infer(body_id.into()))); + let inference_result = + catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_id.into()))); let inference_result = match inference_result { Ok(inference_result) => inference_result, Err(p) => {