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_value(
175        &self,
176        id: crate::rust_ir::AssociatedTyValueId<I>,
177    ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> {
178        let value = self.ws.db().associated_ty_value(id);
179        self.record(value.impl_id);
180        value
181    }
182
183    fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> {
184        self.record(id);
185        self.ws.db().opaque_ty_data(id)
186    }
187
188    fn impls_for_trait(
189        &self,
190        trait_id: TraitId<I>,
191        parameters: &[chalk_ir::GenericArg<I>],
192        binders: &CanonicalVarKinds<I>,
193    ) -> Vec<ImplId<I>> {
194        self.record(trait_id);
195        let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders);
196        self.record_all(impl_ids.iter().copied());
197        impl_ids
198    }
199
200    fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> {
201        self.record(trait_id);
202        self.ws.db().local_impls_to_coherence_check(trait_id)
203    }
204
205    fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool {
206        self.record(auto_trait_id);
207        if let TyKind::Adt(adt_id, _) = ty {
208            self.record(*adt_id);
209        }
210        self.ws.db().impl_provided_for(auto_trait_id, ty)
211    }
212
213    fn well_known_trait_id(
214        &self,
215        well_known_trait: crate::rust_ir::WellKnownTrait,
216    ) -> Option<TraitId<I>> {
217        let trait_id = self.ws.db().well_known_trait_id(well_known_trait);
218        if let Some(id) = trait_id {
219            self.record(id);
220        }
221        trait_id
222    }
223
224    fn program_clauses_for_env(
225        &self,
226        environment: &chalk_ir::Environment<I>,
227    ) -> chalk_ir::ProgramClauses<I> {
228        self.ws.db().program_clauses_for_env(environment)
229    }
230
231    fn interner(&self) -> I {
232        self.ws.db().interner()
233    }
234
235    fn trait_name(&self, trait_id: TraitId<I>) -> String {
236        self.ws.db().trait_name(trait_id)
237    }
238
239    fn adt_name(&self, adt_id: AdtId<I>) -> String {
240        self.ws.db().adt_name(adt_id)
241    }
242
243    fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String {
244        self.ws.db().assoc_type_name(assoc_ty_id)
245    }
246
247    fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String {
248        self.ws.db().opaque_type_name(opaque_ty_id)
249    }
250
251    fn is_object_safe(&self, trait_id: TraitId<I>) -> bool {
252        self.record(trait_id);
253        self.ws.db().is_object_safe(trait_id)
254    }
255
256    fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> {
257        self.record(fn_def_id);
258        self.ws.db().fn_def_datum(fn_def_id)
259    }
260
261    fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String {
262        self.ws.db().fn_def_name(fn_def_id)
263    }
264
265    fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind {
266        // TODO: record closure IDs
267        self.ws.db().closure_kind(closure_id, substs)
268    }
269
270    fn closure_inputs_and_output(
271        &self,
272        closure_id: ClosureId<I>,
273        substs: &Substitution<I>,
274    ) -> Binders<FnDefInputsAndOutputDatum<I>> {
275        // TODO: record closure IDs
276        self.ws.db().closure_inputs_and_output(closure_id, substs)
277    }
278
279    fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> {
280        // TODO: record closure IDs
281        self.ws.db().closure_upvars(closure_id, substs)
282    }
283
284    fn closure_fn_substitution(
285        &self,
286        closure_id: ClosureId<I>,
287        substs: &Substitution<I>,
288    ) -> Substitution<I> {
289        // TODO: record closure IDs
290        self.ws.db().closure_fn_substitution(closure_id, substs)
291    }
292
293    fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> {
294        self.ws.db().discriminant_type(ty)
295    }
296
297    fn unification_database(&self) -> &dyn UnificationDatabase<I> {
298        self
299    }
300}
301
302/// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used
303/// definition to the given file.
304///
305/// Uses [`LoggingRustIrDatabase`] internally.
306///
307/// Uses a separate type, `P`, for the database stored inside to account for
308/// `Arc` or wrapping other storage mediums.
309pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB>
310where
311    I: Interner,
312    W: Write,
313    DB: RustIrDatabase<I>,
314    P: Borrow<DB>,
315{
316    db: LoggingRustIrDatabase<I, DB, P>,
317    write: W,
318}
319
320impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P>
321where
322    I: Interner,
323    W: Write,
324    DB: RustIrDatabase<I>,
325    P: Borrow<DB> + fmt::Debug,
326{
327    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
328        f.debug_struct("WriteOnDropRustIrDatabase")
329            .field("db", &self.db)
330            .field("write", &"<opaque>")
331            .finish()
332    }
333}
334
335impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P>
336where
337    I: Interner,
338    W: Write,
339    DB: RustIrDatabase<I>,
340    P: Borrow<DB>,
341{
342    pub fn new(db: P, write: W) -> Self {
343        WriteOnDropRustIrDatabase {
344            db: LoggingRustIrDatabase::new(db),
345            write,
346        }
347    }
348
349    pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self {
350        WriteOnDropRustIrDatabase { db, write }
351    }
352}
353
354impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P>
355where
356    I: Interner,
357    W: Write,
358    DB: RustIrDatabase<I>,
359    P: Borrow<DB>,
360{
361    fn drop(&mut self) {
362        write!(self.write, "{}", self.db)
363            .and_then(|_| self.write.flush())
364            .expect("expected to be able to write rust ir database");
365    }
366}
367
368impl<I, W, DB, P> UnificationDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P>
369where
370    I: Interner,
371    W: Write,
372    DB: RustIrDatabase<I>,
373    P: Borrow<DB> + Debug,
374{
375    fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> {
376        self.db
377            .borrow()
378            .unification_database()
379            .fn_def_variance(fn_def_id)
380    }
381
382    fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> {
383        self.db.borrow().unification_database().adt_variance(adt_id)
384    }
385}
386
387impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P>
388where
389    I: Interner,
390    W: Write,
391    DB: RustIrDatabase<I>,
392    P: Borrow<DB> + Debug,
393{
394    fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> {
395        self.db.custom_clauses()
396    }
397
398    fn associated_ty_data(
399        &self,
400        ty: chalk_ir::AssocTypeId<I>,
401    ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> {
402        self.db.associated_ty_data(ty)
403    }
404
405    fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> {
406        self.db.trait_datum(trait_id)
407    }
408
409    fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> {
410        self.db.adt_datum(adt_id)
411    }
412
413    fn coroutine_datum(&self, coroutine_id: CoroutineId<I>) -> Arc<CoroutineDatum<I>> {
414        self.db.borrow().coroutine_datum(coroutine_id)
415    }
416
417    /// Returns the coroutine witness datum for the coroutine with the given id.
418    fn coroutine_witness_datum(
419        &self,
420        coroutine_id: CoroutineId<I>,
421    ) -> Arc<CoroutineWitnessDatum<I>> {
422        self.db.borrow().coroutine_witness_datum(coroutine_id)
423    }
424
425    fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> {
426        self.db.adt_repr(id)
427    }
428
429    fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> {
430        self.db.adt_size_align(id)
431    }
432
433    fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> {
434        self.db.impl_datum(impl_id)
435    }
436
437    fn associated_ty_value(
438        &self,
439        id: crate::rust_ir::AssociatedTyValueId<I>,
440    ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> {
441        self.db.associated_ty_value(id)
442    }
443
444    fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> {
445        self.db.opaque_ty_data(id)
446    }
447
448    fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> {
449        self.db.hidden_opaque_type(id)
450    }
451
452    fn impls_for_trait(
453        &self,
454        trait_id: TraitId<I>,
455        parameters: &[chalk_ir::GenericArg<I>],
456        binders: &CanonicalVarKinds<I>,
457    ) -> Vec<ImplId<I>> {
458        self.db.impls_for_trait(trait_id, parameters, binders)
459    }
460
461    fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> {
462        self.db.local_impls_to_coherence_check(trait_id)
463    }
464
465    fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool {
466        self.db.impl_provided_for(auto_trait_id, ty)
467    }
468
469    fn well_known_trait_id(
470        &self,
471        well_known_trait: crate::rust_ir::WellKnownTrait,
472    ) -> Option<TraitId<I>> {
473        self.db.well_known_trait_id(well_known_trait)
474    }
475
476    fn program_clauses_for_env(
477        &self,
478        environment: &chalk_ir::Environment<I>,
479    ) -> chalk_ir::ProgramClauses<I> {
480        self.db.program_clauses_for_env(environment)
481    }
482
483    fn interner(&self) -> I {
484        self.db.interner()
485    }
486
487    fn is_object_safe(&self, trait_id: TraitId<I>) -> bool {
488        self.db.is_object_safe(trait_id)
489    }
490
491    fn unification_database(&self) -> &dyn UnificationDatabase<I> {
492        self
493    }
494
495    fn trait_name(&self, trait_id: TraitId<I>) -> String {
496        self.db.trait_name(trait_id)
497    }
498
499    fn adt_name(&self, adt_id: AdtId<I>) -> String {
500        self.db.adt_name(adt_id)
501    }
502
503    fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String {
504        self.db.assoc_type_name(assoc_ty_id)
505    }
506
507    fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String {
508        self.db.opaque_type_name(opaque_ty_id)
509    }
510
511    fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> {
512        self.db.fn_def_datum(fn_def_id)
513    }
514
515    fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String {
516        self.db.fn_def_name(fn_def_id)
517    }
518
519    fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind {
520        // TODO: record closure IDs
521        self.db.closure_kind(closure_id, substs)
522    }
523
524    fn closure_inputs_and_output(
525        &self,
526        closure_id: ClosureId<I>,
527        substs: &Substitution<I>,
528    ) -> Binders<FnDefInputsAndOutputDatum<I>> {
529        self.db.closure_inputs_and_output(closure_id, substs)
530    }
531
532    fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> {
533        self.db.closure_upvars(closure_id, substs)
534    }
535
536    fn closure_fn_substitution(
537        &self,
538        closure_id: ClosureId<I>,
539        substs: &Substitution<I>,
540    ) -> Substitution<I> {
541        self.db.closure_fn_substitution(closure_id, substs)
542    }
543
544    fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> {
545        self.db.discriminant_type(ty)
546    }
547}
548
549#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
550pub enum RecordedItemId<I: Interner> {
551    Adt(AdtId<I>),
552    Trait(TraitId<I>),
553    Impl(ImplId<I>),
554    OpaqueTy(OpaqueTyId<I>),
555    FnDef(FnDefId<I>),
556    Coroutine(CoroutineId<I>),
557}
558
559impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> {
560    fn from(v: AdtId<I>) -> Self {
561        RecordedItemId::Adt(v)
562    }
563}
564
565impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> {
566    fn from(v: TraitId<I>) -> Self {
567        RecordedItemId::Trait(v)
568    }
569}
570
571impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> {
572    fn from(v: ImplId<I>) -> Self {
573        RecordedItemId::Impl(v)
574    }
575}
576
577impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> {
578    fn from(v: OpaqueTyId<I>) -> Self {
579        RecordedItemId::OpaqueTy(v)
580    }
581}
582
583impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> {
584    fn from(v: FnDefId<I>) -> Self {
585        RecordedItemId::FnDef(v)
586    }
587}
588
589impl<I: Interner> From<CoroutineId<I>> for RecordedItemId<I> {
590    fn from(v: CoroutineId<I>) -> Self {
591        RecordedItemId::Coroutine(v)
592    }
593}