1use 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 fn as_dyn(&self) -> &dyn HirDatabase;
51
52 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 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 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 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 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#[derive(Debug, Hash, PartialEq, Eq, Clone)]
462pub struct AnonConstLoc {
463 pub owner: ExpressionStoreOwnerId,
465 pub expr: ExprId,
468 pub ty: StoredEarlyBinder<StoredTy>,
469 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 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#[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}