1use std::{
4 borrow::Borrow,
5 fmt::{self, Debug, Display},
6 io::Write,
7 marker::PhantomData,
8 sync::Arc,
9 sync::Mutex,
10};
11
12use crate::rust_ir::*;
13use crate::{
14 display::{self, WriterState},
15 RustIrDatabase,
16};
17use chalk_ir::{interner::Interner, *};
18
19use indexmap::IndexSet;
20
21mod id_collector;
22
23#[derive(Debug)]
32pub struct LoggingRustIrDatabase<I, DB, P = DB>
33where
34 DB: RustIrDatabase<I>,
35 P: Borrow<DB>,
36 I: Interner,
37{
38 ws: WriterState<I, DB, P>,
39 def_ids: Mutex<IndexSet<RecordedItemId<I>>>,
40 _phantom: PhantomData<DB>,
41}
42
43impl<I, DB, P> LoggingRustIrDatabase<I, DB, P>
44where
45 DB: RustIrDatabase<I>,
46 P: Borrow<DB>,
47 I: Interner,
48{
49 pub fn new(db: P) -> Self {
50 LoggingRustIrDatabase {
51 ws: WriterState::new(db),
52 def_ids: Default::default(),
53 _phantom: PhantomData,
54 }
55 }
56}
57
58impl<I, DB, P> Display for LoggingRustIrDatabase<I, DB, P>
59where
60 DB: RustIrDatabase<I>,
61 P: Borrow<DB>,
62 I: Interner,
63{
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 let def_ids = self.def_ids.lock().unwrap();
66 let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids);
67 display::write_stub_items(f, &self.ws, stub_ids)?;
68 display::write_items(f, &self.ws, def_ids.iter().copied())
69 }
70}
71
72impl<I, DB, P> LoggingRustIrDatabase<I, DB, P>
73where
74 DB: RustIrDatabase<I>,
75 P: Borrow<DB>,
76 I: Interner,
77{
78 fn record(&self, id: impl Into<RecordedItemId<I>>) {
79 self.def_ids.lock().unwrap().insert(id.into());
80 }
81
82 fn record_all<T, U>(&self, ids: T)
83 where
84 T: IntoIterator<Item = U>,
85 U: Into<RecordedItemId<I>>,
86 {
87 self.def_ids
88 .lock()
89 .unwrap()
90 .extend(ids.into_iter().map(Into::into));
91 }
92}
93
94impl<I, DB, P> UnificationDatabase<I> for LoggingRustIrDatabase<I, DB, P>
95where
96 DB: RustIrDatabase<I>,
97 P: Borrow<DB> + Debug,
98 I: Interner,
99{
100 fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> {
101 self.ws
102 .db()
103 .unification_database()
104 .fn_def_variance(fn_def_id)
105 }
106
107 fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> {
108 self.ws.db().unification_database().adt_variance(adt_id)
109 }
110}
111
112impl<I, DB, P> RustIrDatabase<I> for LoggingRustIrDatabase<I, DB, P>
113where
114 DB: RustIrDatabase<I>,
115 P: Borrow<DB> + Debug,
116 I: Interner,
117{
118 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> {
119 self.ws.db().custom_clauses()
120 }
121
122 fn associated_ty_data(
123 &self,
124 ty: chalk_ir::AssocTypeId<I>,
125 ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> {
126 let ty_datum = self.ws.db().associated_ty_data(ty);
127 self.record(ty_datum.trait_id);
128 ty_datum
129 }
130
131 fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> {
132 self.record(trait_id);
133 self.ws.db().trait_datum(trait_id)
134 }
135
136 fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> {
137 self.record(adt_id);
138 self.ws.db().adt_datum(adt_id)
139 }
140
141 fn coroutine_datum(&self, coroutine_id: CoroutineId<I>) -> Arc<CoroutineDatum<I>> {
142 self.record(coroutine_id);
143 self.ws.db().borrow().coroutine_datum(coroutine_id)
144 }
145
146 fn coroutine_witness_datum(
147 &self,
148 coroutine_id: CoroutineId<I>,
149 ) -> Arc<CoroutineWitnessDatum<I>> {
150 self.record(coroutine_id);
151 self.ws.db().borrow().coroutine_witness_datum(coroutine_id)
152 }
153
154 fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> {
155 self.record(id);
156 self.ws.db().adt_repr(id)
157 }
158
159 fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> {
160 self.record(id);
161 self.ws.db().adt_size_align(id)
162 }
163
164 fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> {
165 self.record(impl_id);
166 self.ws.db().impl_datum(impl_id)
167 }
168
169 fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> {
170 self.record(id);
171 self.ws.db().hidden_opaque_type(id)
172 }
173
174 fn associated_ty_from_impl(
175 &self,
176 impl_id: ImplId<I>,
177 assoc_type_id: AssocTypeId<I>,
178 ) -> Option<AssociatedTyValueId<I>> {
179 self.ws.db().associated_ty_from_impl(impl_id, assoc_type_id)
180 }
181
182 fn associated_ty_value(
183 &self,
184 id: crate::rust_ir::AssociatedTyValueId<I>,
185 ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> {
186 let value = self.ws.db().associated_ty_value(id);
187 self.record(value.impl_id);
188 value
189 }
190
191 fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> {
192 self.record(id);
193 self.ws.db().opaque_ty_data(id)
194 }
195
196 fn impls_for_trait(
197 &self,
198 trait_id: TraitId<I>,
199 parameters: &[chalk_ir::GenericArg<I>],
200 binders: &CanonicalVarKinds<I>,
201 ) -> Vec<ImplId<I>> {
202 self.record(trait_id);
203 let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders);
204 self.record_all(impl_ids.iter().copied());
205 impl_ids
206 }
207
208 fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> {
209 self.record(trait_id);
210 self.ws.db().local_impls_to_coherence_check(trait_id)
211 }
212
213 fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool {
214 self.record(auto_trait_id);
215 if let TyKind::Adt(adt_id, _) = ty {
216 self.record(*adt_id);
217 }
218 self.ws.db().impl_provided_for(auto_trait_id, ty)
219 }
220
221 fn well_known_trait_id(
222 &self,
223 well_known_trait: crate::rust_ir::WellKnownTrait,
224 ) -> Option<TraitId<I>> {
225 let trait_id = self.ws.db().well_known_trait_id(well_known_trait);
226 if let Some(id) = trait_id {
227 self.record(id);
228 }
229 trait_id
230 }
231
232 fn well_known_assoc_type_id(&self, assoc_type: WellKnownAssocType) -> Option<AssocTypeId<I>> {
233 let assoc_type_id = self.ws.db().well_known_assoc_type_id(assoc_type);
234 if let Some(id) = assoc_type_id {
235 self.record(self.ws.db().associated_ty_data(id).trait_id);
236 }
237 assoc_type_id
238 }
239
240 fn program_clauses_for_env(
241 &self,
242 environment: &chalk_ir::Environment<I>,
243 ) -> chalk_ir::ProgramClauses<I> {
244 self.ws.db().program_clauses_for_env(environment)
245 }
246
247 fn interner(&self) -> I {
248 self.ws.db().interner()
249 }
250
251 fn trait_name(&self, trait_id: TraitId<I>) -> String {
252 self.ws.db().trait_name(trait_id)
253 }
254
255 fn adt_name(&self, adt_id: AdtId<I>) -> String {
256 self.ws.db().adt_name(adt_id)
257 }
258
259 fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String {
260 self.ws.db().assoc_type_name(assoc_ty_id)
261 }
262
263 fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String {
264 self.ws.db().opaque_type_name(opaque_ty_id)
265 }
266
267 fn is_object_safe(&self, trait_id: TraitId<I>) -> bool {
268 self.record(trait_id);
269 self.ws.db().is_object_safe(trait_id)
270 }
271
272 fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> {
273 self.record(fn_def_id);
274 self.ws.db().fn_def_datum(fn_def_id)
275 }
276
277 fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String {
278 self.ws.db().fn_def_name(fn_def_id)
279 }
280
281 fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind {
282 self.ws.db().closure_kind(closure_id, substs)
284 }
285
286 fn closure_inputs_and_output(
287 &self,
288 closure_id: ClosureId<I>,
289 substs: &Substitution<I>,
290 ) -> Binders<FnDefInputsAndOutputDatum<I>> {
291 self.ws.db().closure_inputs_and_output(closure_id, substs)
293 }
294
295 fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> {
296 self.ws.db().closure_upvars(closure_id, substs)
298 }
299
300 fn closure_fn_substitution(
301 &self,
302 closure_id: ClosureId<I>,
303 substs: &Substitution<I>,
304 ) -> Substitution<I> {
305 self.ws.db().closure_fn_substitution(closure_id, substs)
307 }
308
309 fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> {
310 self.ws.db().discriminant_type(ty)
311 }
312
313 fn unification_database(&self) -> &dyn UnificationDatabase<I> {
314 self
315 }
316}
317
318pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB>
326where
327 I: Interner,
328 W: Write,
329 DB: RustIrDatabase<I>,
330 P: Borrow<DB>,
331{
332 db: LoggingRustIrDatabase<I, DB, P>,
333 write: W,
334}
335
336impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P>
337where
338 I: Interner,
339 W: Write,
340 DB: RustIrDatabase<I>,
341 P: Borrow<DB> + fmt::Debug,
342{
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 f.debug_struct("WriteOnDropRustIrDatabase")
345 .field("db", &self.db)
346 .field("write", &"<opaque>")
347 .finish()
348 }
349}
350
351impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P>
352where
353 I: Interner,
354 W: Write,
355 DB: RustIrDatabase<I>,
356 P: Borrow<DB>,
357{
358 pub fn new(db: P, write: W) -> Self {
359 WriteOnDropRustIrDatabase {
360 db: LoggingRustIrDatabase::new(db),
361 write,
362 }
363 }
364
365 pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self {
366 WriteOnDropRustIrDatabase { db, write }
367 }
368}
369
370impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P>
371where
372 I: Interner,
373 W: Write,
374 DB: RustIrDatabase<I>,
375 P: Borrow<DB>,
376{
377 fn drop(&mut self) {
378 write!(self.write, "{}", self.db)
379 .and_then(|_| self.write.flush())
380 .expect("expected to be able to write rust ir database");
381 }
382}
383
384impl<I, W, DB, P> UnificationDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P>
385where
386 I: Interner,
387 W: Write,
388 DB: RustIrDatabase<I>,
389 P: Borrow<DB> + Debug,
390{
391 fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> {
392 self.db
393 .borrow()
394 .unification_database()
395 .fn_def_variance(fn_def_id)
396 }
397
398 fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> {
399 self.db.borrow().unification_database().adt_variance(adt_id)
400 }
401}
402
403impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P>
404where
405 I: Interner,
406 W: Write,
407 DB: RustIrDatabase<I>,
408 P: Borrow<DB> + Debug,
409{
410 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> {
411 self.db.custom_clauses()
412 }
413
414 fn associated_ty_data(
415 &self,
416 ty: chalk_ir::AssocTypeId<I>,
417 ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> {
418 self.db.associated_ty_data(ty)
419 }
420
421 fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> {
422 self.db.trait_datum(trait_id)
423 }
424
425 fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> {
426 self.db.adt_datum(adt_id)
427 }
428
429 fn coroutine_datum(&self, coroutine_id: CoroutineId<I>) -> Arc<CoroutineDatum<I>> {
430 self.db.borrow().coroutine_datum(coroutine_id)
431 }
432
433 fn coroutine_witness_datum(
435 &self,
436 coroutine_id: CoroutineId<I>,
437 ) -> Arc<CoroutineWitnessDatum<I>> {
438 self.db.borrow().coroutine_witness_datum(coroutine_id)
439 }
440
441 fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> {
442 self.db.adt_repr(id)
443 }
444
445 fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> {
446 self.db.adt_size_align(id)
447 }
448
449 fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> {
450 self.db.impl_datum(impl_id)
451 }
452
453 fn associated_ty_from_impl(
454 &self,
455 impl_id: ImplId<I>,
456 assoc_type_id: AssocTypeId<I>,
457 ) -> Option<AssociatedTyValueId<I>> {
458 self.db.associated_ty_from_impl(impl_id, assoc_type_id)
459 }
460
461 fn associated_ty_value(
462 &self,
463 id: crate::rust_ir::AssociatedTyValueId<I>,
464 ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> {
465 self.db.associated_ty_value(id)
466 }
467
468 fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> {
469 self.db.opaque_ty_data(id)
470 }
471
472 fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> {
473 self.db.hidden_opaque_type(id)
474 }
475
476 fn impls_for_trait(
477 &self,
478 trait_id: TraitId<I>,
479 parameters: &[chalk_ir::GenericArg<I>],
480 binders: &CanonicalVarKinds<I>,
481 ) -> Vec<ImplId<I>> {
482 self.db.impls_for_trait(trait_id, parameters, binders)
483 }
484
485 fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> {
486 self.db.local_impls_to_coherence_check(trait_id)
487 }
488
489 fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool {
490 self.db.impl_provided_for(auto_trait_id, ty)
491 }
492
493 fn well_known_trait_id(
494 &self,
495 well_known_trait: crate::rust_ir::WellKnownTrait,
496 ) -> Option<TraitId<I>> {
497 self.db.well_known_trait_id(well_known_trait)
498 }
499
500 fn well_known_assoc_type_id(&self, assoc_type: WellKnownAssocType) -> Option<AssocTypeId<I>> {
501 self.db.well_known_assoc_type_id(assoc_type)
502 }
503
504 fn program_clauses_for_env(
505 &self,
506 environment: &chalk_ir::Environment<I>,
507 ) -> chalk_ir::ProgramClauses<I> {
508 self.db.program_clauses_for_env(environment)
509 }
510
511 fn interner(&self) -> I {
512 self.db.interner()
513 }
514
515 fn is_object_safe(&self, trait_id: TraitId<I>) -> bool {
516 self.db.is_object_safe(trait_id)
517 }
518
519 fn unification_database(&self) -> &dyn UnificationDatabase<I> {
520 self
521 }
522
523 fn trait_name(&self, trait_id: TraitId<I>) -> String {
524 self.db.trait_name(trait_id)
525 }
526
527 fn adt_name(&self, adt_id: AdtId<I>) -> String {
528 self.db.adt_name(adt_id)
529 }
530
531 fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String {
532 self.db.assoc_type_name(assoc_ty_id)
533 }
534
535 fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String {
536 self.db.opaque_type_name(opaque_ty_id)
537 }
538
539 fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> {
540 self.db.fn_def_datum(fn_def_id)
541 }
542
543 fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String {
544 self.db.fn_def_name(fn_def_id)
545 }
546
547 fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind {
548 self.db.closure_kind(closure_id, substs)
550 }
551
552 fn closure_inputs_and_output(
553 &self,
554 closure_id: ClosureId<I>,
555 substs: &Substitution<I>,
556 ) -> Binders<FnDefInputsAndOutputDatum<I>> {
557 self.db.closure_inputs_and_output(closure_id, substs)
558 }
559
560 fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> {
561 self.db.closure_upvars(closure_id, substs)
562 }
563
564 fn closure_fn_substitution(
565 &self,
566 closure_id: ClosureId<I>,
567 substs: &Substitution<I>,
568 ) -> Substitution<I> {
569 self.db.closure_fn_substitution(closure_id, substs)
570 }
571
572 fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> {
573 self.db.discriminant_type(ty)
574 }
575}
576
577#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
578pub enum RecordedItemId<I: Interner> {
579 Adt(AdtId<I>),
580 Trait(TraitId<I>),
581 Impl(ImplId<I>),
582 OpaqueTy(OpaqueTyId<I>),
583 FnDef(FnDefId<I>),
584 Coroutine(CoroutineId<I>),
585}
586
587impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> {
588 fn from(v: AdtId<I>) -> Self {
589 RecordedItemId::Adt(v)
590 }
591}
592
593impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> {
594 fn from(v: TraitId<I>) -> Self {
595 RecordedItemId::Trait(v)
596 }
597}
598
599impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> {
600 fn from(v: ImplId<I>) -> Self {
601 RecordedItemId::Impl(v)
602 }
603}
604
605impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> {
606 fn from(v: OpaqueTyId<I>) -> Self {
607 RecordedItemId::OpaqueTy(v)
608 }
609}
610
611impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> {
612 fn from(v: FnDefId<I>) -> Self {
613 RecordedItemId::FnDef(v)
614 }
615}
616
617impl<I: Interner> From<CoroutineId<I>> for RecordedItemId<I> {
618 fn from(v: CoroutineId<I>) -> Self {
619 RecordedItemId::Coroutine(v)
620 }
621}