Skip to main content

hir_ty/
db.rs

1//! The home of `HirDatabase`, which is the Salsa database containing all the
2//! type inference-related queries.
3
4use std::sync::LazyLock;
5
6use arrayvec::ArrayVec;
7use base_db::{Crate, SourceDatabase, target::TargetLoadError};
8use either::Either;
9use hir_def::{
10    AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, EnumVariantId,
11    ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, ImplId, LocalFieldId, ModuleId,
12    StaticId, TraitId, TypeAliasId, VariantId,
13    builtin_derive::BuiltinDeriveImplMethod,
14    expr_store::ExpressionStore,
15    hir::{ClosureKind, ExprId},
16    layout::TargetDataLayout,
17    resolver::{HasResolver, Resolver},
18    signatures::{ConstSignature, StaticSignature},
19};
20use la_arena::ArenaMap;
21use salsa::SalsaValue;
22use span::Edition;
23use stdx::impl_from;
24use triomphe::Arc;
25
26use crate::{
27    FieldType, GenericDefaultsRef, GenericPredicates, ImplTraitId, InferBodyId, TyDefId,
28    TyLoweringDiagnostic, TyLoweringResult, ValueTyDefId,
29    consteval::ConstEvalError,
30    dyn_compatibility::DynCompatibilityViolation,
31    layout::{Layout, LayoutError},
32    lower::{
33        ConstParamTypes, FieldTypes, GenericDefaults, SelfAndAssocBounds, TrackedStructToken,
34        WithDefinedOpaques,
35    },
36    mir::{MirBody, MirLowerError},
37    next_solver::{
38        Allocation, Clause, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, StoredEarlyBinder,
39        StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitRef, Ty, VariancesOf,
40    },
41    traits::{ParamEnvAndCrate, StoredParamEnvAndCrate},
42};
43
44#[salsa::db]
45pub trait HirDatabase: SourceDatabase + 'static {
46    /// Manual implementation of upcasting from `dyn SourceDatabase` to `dyn HirDatabase`.
47    ///
48    /// This function is needed because Rust can't perform this upcasting automatically
49    /// in the general case, as `Self` could be unsized.
50    fn as_dyn(&self) -> &dyn HirDatabase;
51
52    // region:mir
53
54    // FIXME: Collapse `mir_body_for_closure` into `mir_body`
55    // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body`
56    fn mir_body<'db>(
57        &'db self,
58        def: InferBodyId<'db>,
59    ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> {
60        let db = self.as_dyn();
61        crate::mir::mir_body_query(db, def).map_err(|err| err.clone())
62    }
63
64    fn mir_body_for_closure<'db>(
65        &'db self,
66        def: InternedClosureId<'db>,
67    ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> {
68        let db = self.as_dyn();
69        crate::mir::mir_body_for_closure_query(db, def).map_err(|err| err.clone())
70    }
71
72    fn monomorphized_mir_body<'db>(
73        &'db self,
74        def: InferBodyId<'db>,
75        subst: StoredGenericArgs,
76        env: StoredParamEnvAndCrate,
77    ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> {
78        let db = self.as_dyn();
79        crate::mir::monomorphized_mir_body_query(db, def, subst, env).map_err(|err| err.clone())
80    }
81
82    fn monomorphized_mir_body_for_closure<'db>(
83        &'db self,
84        def: InternedClosureId<'db>,
85        subst: StoredGenericArgs,
86        env: StoredParamEnvAndCrate,
87    ) -> Result<&'db MirBody<'db>, MirLowerError<'db>> {
88        let db = self.as_dyn();
89        crate::mir::monomorphized_mir_body_for_closure_query(db, def, subst, env)
90            .map_err(|err| err.clone())
91    }
92
93    fn const_eval<'db>(
94        &'db self,
95        def: ConstId,
96        subst: GenericArgs<'db>,
97        trait_env: Option<ParamEnvAndCrate<'db>>,
98    ) -> Result<Allocation<'db>, ConstEvalError<'db>> {
99        let db = self.as_dyn();
100        crate::consteval::const_eval(db, def, subst, trait_env)
101    }
102
103    fn anon_const_eval<'db>(
104        &'db self,
105        def: AnonConstId<'db>,
106        subst: GenericArgs<'db>,
107        trait_env: Option<ParamEnvAndCrate<'db>>,
108    ) -> Result<Allocation<'db>, ConstEvalError<'db>> {
109        let db = self.as_dyn();
110        crate::consteval::anon_const_eval(db, def, subst, trait_env)
111    }
112
113    fn const_eval_static<'db>(
114        &'db self,
115        def: StaticId,
116    ) -> Result<Allocation<'db>, ConstEvalError<'db>> {
117        let db = self.as_dyn();
118        crate::consteval::const_eval_static(db, def)
119    }
120
121    fn const_eval_discriminant<'db>(
122        &'db self,
123        def: EnumVariantId,
124    ) -> Result<i128, ConstEvalError<'db>> {
125        let db = self.as_dyn();
126        crate::consteval::const_eval_discriminant_variant(db, def)
127    }
128
129    fn lookup_impl_method<'db>(
130        &'db self,
131        env: ParamEnvAndCrate<'db>,
132        func: FunctionId,
133        fn_subst: GenericArgs<'db>,
134    ) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>)
135    {
136        let db = self.as_dyn();
137        crate::method_resolution::lookup_impl_method_query(db, env, func, fn_subst)
138    }
139
140    // endregion:mir
141
142    fn layout_of_adt(
143        &self,
144        def: AdtId,
145        args: StoredGenericArgs,
146        trait_env: StoredParamEnvAndCrate,
147    ) -> Result<Arc<Layout>, LayoutError> {
148        let db = self.as_dyn();
149        crate::layout::layout_of_adt_query(db, def, args, trait_env)
150    }
151
152    fn layout_of_ty(
153        &self,
154        ty: StoredTy,
155        env: StoredParamEnvAndCrate,
156    ) -> Result<Arc<Layout>, LayoutError> {
157        let db = self.as_dyn();
158        crate::layout::layout_of_ty_query(db, ty, env)
159    }
160
161    fn target_data_layout(&self, krate: Crate) -> Result<&TargetDataLayout, TargetLoadError> {
162        let db = self.as_dyn();
163        crate::layout::target_data_layout_query(db, krate).map_err(|err| err.clone())
164    }
165
166    fn target_data_layout_or_default(&self, krate: Crate) -> &TargetDataLayout {
167        static DEFAULT: LazyLock<TargetDataLayout> = LazyLock::new(TargetDataLayout::default);
168
169        let db = self.as_dyn();
170        crate::layout::target_data_layout_query(db, krate).unwrap_or_else(|_| &*DEFAULT)
171    }
172
173    fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation> {
174        let db = self.as_dyn();
175        crate::dyn_compatibility::dyn_compatibility_of_trait_query(db, trait_)
176    }
177
178    fn ty<'db>(&'db self, def: TyDefId) -> EarlyBinder<'db, Ty<'db>> {
179        let db = self.as_dyn();
180        crate::lower::ty_query(db, def)
181    }
182
183    fn type_for_type_alias_with_diagnostics<'db>(
184        &'db self,
185        def: TypeAliasId,
186    ) -> &'db TyLoweringResult<'db, WithDefinedOpaques<StoredEarlyBinder<StoredTy>>> {
187        let db = self.as_dyn();
188        crate::lower::type_for_type_alias_with_diagnostics(db, def)
189    }
190
191    /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
192    /// a `StructId` or `EnumVariantId` with a record constructor.
193    fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option<EarlyBinder<'db, Ty<'db>>> {
194        let db = self.as_dyn();
195        crate::lower::value_ty(db, def)
196    }
197
198    fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>> {
199        let db = self.as_dyn();
200        crate::lower::type_for_const(db, def)
201    }
202
203    fn type_for_const_with_diagnostics<'db>(
204        &'db self,
205        def: ConstId,
206    ) -> &'db TyLoweringResult<'db, StoredEarlyBinder<StoredTy>> {
207        let db = self.as_dyn();
208        crate::lower::type_for_const_with_diagnostics(db, def)
209    }
210
211    fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>> {
212        let db = self.as_dyn();
213        crate::lower::type_for_static(db, def)
214    }
215
216    fn type_for_static_with_diagnostics<'db>(
217        &'db self,
218        def: StaticId,
219    ) -> &'db TyLoweringResult<'db, StoredEarlyBinder<StoredTy>> {
220        let db = self.as_dyn();
221        crate::lower::type_for_static_with_diagnostics(db, def)
222    }
223
224    fn impl_self_ty_with_diagnostics<'db>(
225        &'db self,
226        def: ImplId,
227    ) -> &'db TyLoweringResult<'db, StoredEarlyBinder<StoredTy>> {
228        let db = self.as_dyn();
229        crate::lower::impl_self_ty_with_diagnostics(db, def)
230    }
231
232    fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>> {
233        let db = self.as_dyn();
234        crate::lower::impl_self_ty_query(db, def)
235    }
236
237    fn const_param_types_with_diagnostics<'db>(
238        &'db self,
239        def: GenericDefId,
240    ) -> &'db TyLoweringResult<'db, ConstParamTypes> {
241        let db = self.as_dyn();
242        crate::lower::const_param_types_with_diagnostics(db, def)
243    }
244
245    fn const_param_types(&self, def: GenericDefId) -> &ConstParamTypes {
246        let db = self.as_dyn();
247        crate::lower::const_param_types(db, def)
248    }
249
250    fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db> {
251        let db = self.as_dyn();
252        crate::lower::const_param_ty(db, def)
253    }
254
255    fn impl_trait_with_diagnostics<'db>(
256        &'db self,
257        def: ImplId,
258    ) -> &'db Option<TyLoweringResult<'db, StoredEarlyBinder<StoredTraitRef>>> {
259        let db = self.as_dyn();
260        crate::lower::impl_trait_with_diagnostics(db, def)
261    }
262
263    fn impl_trait<'db>(&'db self, def: ImplId) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
264        let db = self.as_dyn();
265        crate::lower::impl_trait_query(db, def)
266    }
267
268    fn field_types_with_diagnostics<'db>(
269        &'db self,
270        var: VariantId,
271    ) -> &'db TyLoweringResult<'db, FieldTypes> {
272        let db = self.as_dyn();
273        crate::lower::field_types_with_diagnostics(db, var)
274    }
275
276    fn field_types(&self, var: VariantId) -> &ArenaMap<LocalFieldId, FieldType> {
277        let db = self.as_dyn();
278        crate::lower::field_types_query(db, var)
279    }
280
281    fn callable_item_signature<'db>(
282        &'db self,
283        def: CallableDefId,
284    ) -> EarlyBinder<'db, PolyFnSig<'db>> {
285        let db = self.as_dyn();
286        crate::lower::callable_item_signature(db, def)
287    }
288
289    fn fn_sig_for_fn_with_diagnostics<'db>(
290        &'db self,
291        def: FunctionId,
292    ) -> &'db TyLoweringResult<'db, WithDefinedOpaques<StoredEarlyBinder<StoredPolyFnSig>>> {
293        let db = self.as_dyn();
294        crate::lower::fn_sig_for_fn(db, def)
295    }
296
297    fn trait_environment<'db>(&'db self, def: GenericDefId) -> ParamEnv<'db> {
298        let db = self.as_dyn();
299        crate::lower::trait_environment(db, def)
300    }
301
302    fn generic_defaults_with_diagnostics<'db>(
303        &'db self,
304        def: GenericDefId,
305    ) -> &'db TyLoweringResult<'db, GenericDefaults> {
306        let db = self.as_dyn();
307        crate::lower::generic_defaults_with_diagnostics(db, def)
308    }
309
310    /// This returns an empty list if no parameter has default.
311    ///
312    /// The binders of the returned defaults are only up to (not including) this parameter.
313    fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_> {
314        let db = self.as_dyn();
315        crate::lower::generic_defaults(db, def)
316    }
317
318    fn type_alias_bounds_with_diagnostics<'db>(
319        &'db self,
320        type_alias: TypeAliasId,
321    ) -> &'db TyLoweringResult<'db, SelfAndAssocBounds> {
322        let db = self.as_dyn();
323        crate::lower::type_alias_bounds_with_diagnostics(db, type_alias)
324    }
325
326    fn type_alias_bounds<'db>(
327        &'db self,
328        type_alias: TypeAliasId,
329    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
330        let db = self.as_dyn();
331        crate::lower::type_alias_bounds(db, type_alias)
332    }
333
334    fn type_alias_self_bounds<'db>(
335        &'db self,
336        type_alias: TypeAliasId,
337    ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
338        let db = self.as_dyn();
339        crate::lower::type_alias_self_bounds(db, type_alias)
340    }
341
342    fn variances_of<'db>(&'db self, def: GenericDefId) -> VariancesOf<'db> {
343        let db = self.as_dyn();
344        crate::variance::variances_of(db, def)
345    }
346
347    // HACK: We need this for MIR intrinsic `type_name()`, and it can't access the display infra because it is inside `hir-ide`.
348    fn type_name<'db>(&'db self, ty: Ty<'db>, module: ModuleId) -> String;
349}
350
351#[test]
352fn hir_database_is_dyn_compatible() {
353    fn _assert_dyn_compatible(_: &dyn HirDatabase) {}
354}
355
356#[salsa::interned(debug, revisions = usize::MAX)]
357#[derive(PartialOrd, Ord)]
358pub struct InternedOpaqueTyId {
359    #[returns(copy)]
360    pub loc: ImplTraitId,
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, SalsaValue)]
364pub struct InternedClosure<'db> {
365    pub owner: InferBodyId<'db>,
366    pub expr: ExprId,
367    pub kind: ClosureKind,
368}
369
370#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)]
371#[derive(PartialOrd, Ord)]
372pub struct InternedClosureId<'db> {
373    #[returns(copy)]
374    pub loc: InternedClosure<'db>,
375}
376
377impl<'db> InternedClosureId<'db> {
378    #[inline]
379    pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self {
380        if cfg!(debug_assertions) {
381            let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db));
382            let expr = &store[loc.expr];
383            assert!(
384                matches!(
385                    expr,
386                    hir_def::hir::Expr::Closure {
387                        closure_kind: hir_def::hir::ClosureKind::Closure,
388                        ..
389                    }
390                ),
391                "expected a closure, found {expr:?}"
392            );
393        }
394
395        Self::new_impl(db, loc)
396    }
397}
398
399#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)]
400#[derive(PartialOrd, Ord)]
401pub struct InternedCoroutineId<'db> {
402    #[returns(copy)]
403    pub loc: InternedClosure<'db>,
404}
405
406impl<'db> InternedCoroutineId<'db> {
407    #[inline]
408    pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self {
409        if cfg!(debug_assertions) {
410            let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db));
411            let expr = &store[loc.expr];
412            assert!(
413                matches!(
414                    expr,
415                    hir_def::hir::Expr::Closure {
416                        closure_kind: hir_def::hir::ClosureKind::OldCoroutine(_)
417                            | hir_def::hir::ClosureKind::Coroutine { .. },
418                        ..
419                    }
420                ),
421                "expected a coroutine, found {expr:?}"
422            );
423        }
424
425        Self::new_impl(db, loc)
426    }
427}
428
429#[salsa::interned(constructor = new_impl, debug, revisions = usize::MAX)]
430#[derive(PartialOrd, Ord)]
431pub struct InternedCoroutineClosureId<'db> {
432    #[returns(copy)]
433    pub loc: InternedClosure<'db>,
434}
435
436impl<'db> InternedCoroutineClosureId<'db> {
437    #[inline]
438    pub fn new(db: &'db dyn HirDatabase, loc: InternedClosure<'db>) -> Self {
439        if cfg!(debug_assertions) {
440            let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db));
441            let expr = &store[loc.expr];
442            assert!(
443                matches!(
444                    expr,
445                    hir_def::hir::Expr::Closure {
446                        closure_kind: hir_def::hir::ClosureKind::CoroutineClosure(_),
447                        ..
448                    }
449                ),
450                "expected a coroutine closure, found {expr:?}"
451            );
452        }
453
454        Self::new_impl(db, loc)
455    }
456}
457
458/// An anonymous const expression that appears in a type position (e.g., array lengths,
459/// const generic arguments like `{ N + 1 }`, or const param defaults). Unlike named constants,
460/// these don't have their own `Body` — their expressions live in the parent's signature `ExpressionStore`.
461#[derive(Debug, Hash, PartialEq, Eq, Clone)]
462pub struct AnonConstLoc {
463    /// The owner store containing this expression.
464    pub owner: ExpressionStoreOwnerId,
465    /// The ExprId within the owner's ExpressionStore that is the root
466    /// of this anonymous const expression.
467    pub expr: ExprId,
468    pub ty: StoredEarlyBinder<StoredTy>,
469    /// Whether to allow using generic params from the owner.
470    /// true for array repeats, false for everything else.
471    pub(crate) allow_using_generic_params: bool,
472}
473
474#[salsa::interned(debug, revisions = usize::MAX, constructor = new_)]
475#[derive(PartialOrd, Ord)]
476pub struct AnonConstId {
477    #[returns(ref)]
478    pub loc: AnonConstLoc,
479}
480
481impl<'db> AnonConstId<'db> {
482    pub(crate) fn new(
483        db: &'db dyn SourceDatabase,
484        loc: AnonConstLoc,
485        token: TrackedStructToken,
486    ) -> Self {
487        _ = token;
488        AnonConstId::new_(db, loc)
489    }
490}
491
492impl HasModule for AnonConstId<'_> {
493    fn module(&self, db: &dyn SourceDatabase) -> ModuleId {
494        self.loc(db).owner.module(db)
495    }
496}
497
498impl HasResolver for AnonConstId<'_> {
499    fn resolver(self, db: &dyn SourceDatabase) -> Resolver<'_> {
500        self.loc(db).owner.resolver(db)
501    }
502}
503
504pub fn signature_anon_consts_and_diagnostics<'db>(
505    db: &'db dyn HirDatabase,
506    def: GenericDefId,
507) -> ArrayVec<(&'db [AnonConstId<'db>], &'db [TyLoweringDiagnostic]), 5> {
508    let mut result = ArrayVec::new();
509
510    // Queries common to all generic defs:
511    push(&mut result, db.generic_defaults_with_diagnostics(def));
512    push(&mut result, GenericPredicates::query_with_diagnostics(db, def));
513    push(&mut result, db.const_param_types_with_diagnostics(def));
514
515    match def {
516        GenericDefId::ImplId(id) => {
517            push(&mut result, db.impl_self_ty_with_diagnostics(id));
518            if let Some(trait_ref) = db.impl_trait_with_diagnostics(id) {
519                push(&mut result, trait_ref);
520            }
521        }
522        GenericDefId::TypeAliasId(id) => {
523            push(&mut result, db.type_for_type_alias_with_diagnostics(id));
524            push(&mut result, db.type_alias_bounds_with_diagnostics(id));
525        }
526        GenericDefId::FunctionId(id) => push(&mut result, db.fn_sig_for_fn_with_diagnostics(id)),
527        GenericDefId::ConstId(def) => push(&mut result, db.type_for_const_with_diagnostics(def)),
528        GenericDefId::StaticId(def) => push(&mut result, db.type_for_static_with_diagnostics(def)),
529        GenericDefId::TraitId(_) | GenericDefId::AdtId(_) => {}
530    }
531
532    return result;
533
534    fn push<'db, T>(
535        result: &mut ArrayVec<(&'db [AnonConstId<'db>], &'db [TyLoweringDiagnostic]), 5>,
536        item: &'db TyLoweringResult<'db, T>,
537    ) {
538        result.push((item.defined_anon_consts(), item.diagnostics()));
539    }
540}
541
542impl<'db> AnonConstId<'db> {
543    pub fn all_from_signature(
544        db: &'db dyn HirDatabase,
545        def: GenericDefId,
546    ) -> impl Iterator<Item = AnonConstId<'db>> {
547        signature_anon_consts_and_diagnostics(db, def)
548            .into_iter()
549            .flat_map(|(anon_consts, _)| anon_consts)
550            .copied()
551    }
552}
553
554/// A constant, which might appears as a const item, an anonymous const block in expressions
555/// or patterns, or as a constant in types with const generics.
556#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)]
557pub enum GeneralConstId<'db> {
558    ConstId(ConstId),
559    StaticId(StaticId),
560    AnonConstId(AnonConstId<'db>),
561}
562
563impl_from!(impl<'db> ConstId, StaticId, AnonConstId<'db> for GeneralConstId<'db>);
564
565impl<'db> GeneralConstId<'db> {
566    pub fn generic_def(self, db: &'db dyn HirDatabase) -> Option<GenericDefId> {
567        match self {
568            GeneralConstId::ConstId(it) => Some(it.into()),
569            GeneralConstId::StaticId(it) => Some(it.into()),
570            GeneralConstId::AnonConstId(it) => Some(it.loc(db).owner.generic_def(db)),
571        }
572    }
573
574    pub fn name(self, db: &'db dyn SourceDatabase) -> String {
575        match self {
576            GeneralConstId::StaticId(it) => {
577                StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string()
578            }
579            GeneralConstId::ConstId(const_id) => {
580                ConstSignature::of(db, const_id).name.as_ref().map_or_else(
581                    || "_".to_owned(),
582                    |name| name.display(db, Edition::CURRENT).to_string(),
583                )
584            }
585            GeneralConstId::AnonConstId(_) => "{const}".to_owned(),
586        }
587    }
588}