chalk_solve/
logging_db.rs

1//! Provides wrappers over `RustIrDatabase` which record used definitions and write
2//! `.chalk` files containing those definitions.
3use 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/// Wraps another `RustIrDatabase` (`DB`) and records which definitions are
24/// used.
25///
26/// A full .chalk file containing all used definitions can be recovered through
27/// `LoggingRustIrDatabase`'s `Display` implementation.
28///
29/// Uses a separate type, `P`, for the database stored inside to account for
30/// `Arc` or wrapping other storage mediums.
31#[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        // TODO: record closure IDs
283        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        // TODO: record closure IDs
292        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        // TODO: record closure IDs
297        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        // TODO: record closure IDs
306        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
318/// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used
319/// definition to the given file.
320///
321/// Uses [`LoggingRustIrDatabase`] internally.
322///
323/// Uses a separate type, `P`, for the database stored inside to account for
324/// `Arc` or wrapping other storage mediums.
325pub 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    /// Returns the coroutine witness datum for the coroutine with the given id.
434    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        // TODO: record closure IDs
549        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}