| //! Provides wrappers over `RustIrDatabase` which record used definitions and write |
| //! `.chalk` files containing those definitions. |
| use std::{ |
| borrow::Borrow, |
| fmt::{self, Debug, Display}, |
| io::Write, |
| marker::PhantomData, |
| sync::Arc, |
| sync::Mutex, |
| }; |
| |
| use crate::rust_ir::*; |
| use crate::{ |
| display::{self, WriterState}, |
| RustIrDatabase, |
| }; |
| use chalk_ir::{interner::Interner, *}; |
| |
| use indexmap::IndexSet; |
| |
| mod id_collector; |
| |
| /// Wraps another `RustIrDatabase` (`DB`) and records which definitions are |
| /// used. |
| /// |
| /// A full .chalk file containing all used definitions can be recovered through |
| /// `LoggingRustIrDatabase`'s `Display` implementation. |
| /// |
| /// Uses a separate type, `P`, for the database stored inside to account for |
| /// `Arc` or wrapping other storage mediums. |
| #[derive(Debug)] |
| pub struct LoggingRustIrDatabase<I, DB, P = DB> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| I: Interner, |
| { |
| ws: WriterState<I, DB, P>, |
| def_ids: Mutex<IndexSet<RecordedItemId<I>>>, |
| _phantom: PhantomData<DB>, |
| } |
| |
| impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| I: Interner, |
| { |
| pub fn new(db: P) -> Self { |
| LoggingRustIrDatabase { |
| ws: WriterState::new(db), |
| def_ids: Default::default(), |
| _phantom: PhantomData, |
| } |
| } |
| } |
| |
| impl<I, DB, P> Display for LoggingRustIrDatabase<I, DB, P> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| I: Interner, |
| { |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| let def_ids = self.def_ids.lock().unwrap(); |
| let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids); |
| display::write_stub_items(f, &self.ws, stub_ids)?; |
| display::write_items(f, &self.ws, def_ids.iter().copied()) |
| } |
| } |
| |
| impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| I: Interner, |
| { |
| fn record(&self, id: impl Into<RecordedItemId<I>>) { |
| self.def_ids.lock().unwrap().insert(id.into()); |
| } |
| |
| fn record_all<T, U>(&self, ids: T) |
| where |
| T: IntoIterator<Item = U>, |
| U: Into<RecordedItemId<I>>, |
| { |
| self.def_ids |
| .lock() |
| .unwrap() |
| .extend(ids.into_iter().map(Into::into)); |
| } |
| } |
| |
| impl<I, DB, P> UnificationDatabase<I> for LoggingRustIrDatabase<I, DB, P> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB> + Debug, |
| I: Interner, |
| { |
| fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> { |
| self.ws |
| .db() |
| .unification_database() |
| .fn_def_variance(fn_def_id) |
| } |
| |
| fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> { |
| self.ws.db().unification_database().adt_variance(adt_id) |
| } |
| } |
| |
| impl<I, DB, P> RustIrDatabase<I> for LoggingRustIrDatabase<I, DB, P> |
| where |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB> + Debug, |
| I: Interner, |
| { |
| fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { |
| self.ws.db().custom_clauses() |
| } |
| |
| fn associated_ty_data( |
| &self, |
| ty: chalk_ir::AssocTypeId<I>, |
| ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { |
| let ty_datum = self.ws.db().associated_ty_data(ty); |
| self.record(ty_datum.trait_id); |
| ty_datum |
| } |
| |
| fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { |
| self.record(trait_id); |
| self.ws.db().trait_datum(trait_id) |
| } |
| |
| fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { |
| self.record(adt_id); |
| self.ws.db().adt_datum(adt_id) |
| } |
| |
| fn coroutine_datum(&self, coroutine_id: CoroutineId<I>) -> Arc<CoroutineDatum<I>> { |
| self.record(coroutine_id); |
| self.ws.db().borrow().coroutine_datum(coroutine_id) |
| } |
| |
| fn coroutine_witness_datum( |
| &self, |
| coroutine_id: CoroutineId<I>, |
| ) -> Arc<CoroutineWitnessDatum<I>> { |
| self.record(coroutine_id); |
| self.ws.db().borrow().coroutine_witness_datum(coroutine_id) |
| } |
| |
| fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> { |
| self.record(id); |
| self.ws.db().adt_repr(id) |
| } |
| |
| fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> { |
| self.record(id); |
| self.ws.db().adt_size_align(id) |
| } |
| |
| fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { |
| self.record(impl_id); |
| self.ws.db().impl_datum(impl_id) |
| } |
| |
| fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { |
| self.record(id); |
| self.ws.db().hidden_opaque_type(id) |
| } |
| |
| fn associated_ty_value( |
| &self, |
| id: crate::rust_ir::AssociatedTyValueId<I>, |
| ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { |
| let value = self.ws.db().associated_ty_value(id); |
| self.record(value.impl_id); |
| value |
| } |
| |
| fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { |
| self.record(id); |
| self.ws.db().opaque_ty_data(id) |
| } |
| |
| fn impls_for_trait( |
| &self, |
| trait_id: TraitId<I>, |
| parameters: &[chalk_ir::GenericArg<I>], |
| binders: &CanonicalVarKinds<I>, |
| ) -> Vec<ImplId<I>> { |
| self.record(trait_id); |
| let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders); |
| self.record_all(impl_ids.iter().copied()); |
| impl_ids |
| } |
| |
| fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { |
| self.record(trait_id); |
| self.ws.db().local_impls_to_coherence_check(trait_id) |
| } |
| |
| fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool { |
| self.record(auto_trait_id); |
| if let TyKind::Adt(adt_id, _) = ty { |
| self.record(*adt_id); |
| } |
| self.ws.db().impl_provided_for(auto_trait_id, ty) |
| } |
| |
| fn well_known_trait_id( |
| &self, |
| well_known_trait: crate::rust_ir::WellKnownTrait, |
| ) -> Option<TraitId<I>> { |
| let trait_id = self.ws.db().well_known_trait_id(well_known_trait); |
| if let Some(id) = trait_id { |
| self.record(id); |
| } |
| trait_id |
| } |
| |
| fn program_clauses_for_env( |
| &self, |
| environment: &chalk_ir::Environment<I>, |
| ) -> chalk_ir::ProgramClauses<I> { |
| self.ws.db().program_clauses_for_env(environment) |
| } |
| |
| fn interner(&self) -> I { |
| self.ws.db().interner() |
| } |
| |
| fn trait_name(&self, trait_id: TraitId<I>) -> String { |
| self.ws.db().trait_name(trait_id) |
| } |
| |
| fn adt_name(&self, adt_id: AdtId<I>) -> String { |
| self.ws.db().adt_name(adt_id) |
| } |
| |
| fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { |
| self.ws.db().assoc_type_name(assoc_ty_id) |
| } |
| |
| fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { |
| self.ws.db().opaque_type_name(opaque_ty_id) |
| } |
| |
| fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { |
| self.record(trait_id); |
| self.ws.db().is_object_safe(trait_id) |
| } |
| |
| fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { |
| self.record(fn_def_id); |
| self.ws.db().fn_def_datum(fn_def_id) |
| } |
| |
| fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { |
| self.ws.db().fn_def_name(fn_def_id) |
| } |
| |
| fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { |
| // TODO: record closure IDs |
| self.ws.db().closure_kind(closure_id, substs) |
| } |
| |
| fn closure_inputs_and_output( |
| &self, |
| closure_id: ClosureId<I>, |
| substs: &Substitution<I>, |
| ) -> Binders<FnDefInputsAndOutputDatum<I>> { |
| // TODO: record closure IDs |
| self.ws.db().closure_inputs_and_output(closure_id, substs) |
| } |
| |
| fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { |
| // TODO: record closure IDs |
| self.ws.db().closure_upvars(closure_id, substs) |
| } |
| |
| fn closure_fn_substitution( |
| &self, |
| closure_id: ClosureId<I>, |
| substs: &Substitution<I>, |
| ) -> Substitution<I> { |
| // TODO: record closure IDs |
| self.ws.db().closure_fn_substitution(closure_id, substs) |
| } |
| |
| fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> { |
| self.ws.db().discriminant_type(ty) |
| } |
| |
| fn unification_database(&self) -> &dyn UnificationDatabase<I> { |
| self |
| } |
| } |
| |
| /// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used |
| /// definition to the given file. |
| /// |
| /// Uses [`LoggingRustIrDatabase`] internally. |
| /// |
| /// Uses a separate type, `P`, for the database stored inside to account for |
| /// `Arc` or wrapping other storage mediums. |
| pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| { |
| db: LoggingRustIrDatabase<I, DB, P>, |
| write: W, |
| } |
| |
| impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB> + fmt::Debug, |
| { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| f.debug_struct("WriteOnDropRustIrDatabase") |
| .field("db", &self.db) |
| .field("write", &"<opaque>") |
| .finish() |
| } |
| } |
| |
| impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| { |
| pub fn new(db: P, write: W) -> Self { |
| WriteOnDropRustIrDatabase { |
| db: LoggingRustIrDatabase::new(db), |
| write, |
| } |
| } |
| |
| pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self { |
| WriteOnDropRustIrDatabase { db, write } |
| } |
| } |
| |
| impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB>, |
| { |
| fn drop(&mut self) { |
| write!(self.write, "{}", self.db) |
| .and_then(|_| self.write.flush()) |
| .expect("expected to be able to write rust ir database"); |
| } |
| } |
| |
| impl<I, W, DB, P> UnificationDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB> + Debug, |
| { |
| fn fn_def_variance(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Variances<I> { |
| self.db |
| .borrow() |
| .unification_database() |
| .fn_def_variance(fn_def_id) |
| } |
| |
| fn adt_variance(&self, adt_id: chalk_ir::AdtId<I>) -> Variances<I> { |
| self.db.borrow().unification_database().adt_variance(adt_id) |
| } |
| } |
| |
| impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> |
| where |
| I: Interner, |
| W: Write, |
| DB: RustIrDatabase<I>, |
| P: Borrow<DB> + Debug, |
| { |
| fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { |
| self.db.custom_clauses() |
| } |
| |
| fn associated_ty_data( |
| &self, |
| ty: chalk_ir::AssocTypeId<I>, |
| ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { |
| self.db.associated_ty_data(ty) |
| } |
| |
| fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { |
| self.db.trait_datum(trait_id) |
| } |
| |
| fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { |
| self.db.adt_datum(adt_id) |
| } |
| |
| fn coroutine_datum(&self, coroutine_id: CoroutineId<I>) -> Arc<CoroutineDatum<I>> { |
| self.db.borrow().coroutine_datum(coroutine_id) |
| } |
| |
| /// Returns the coroutine witness datum for the coroutine with the given id. |
| fn coroutine_witness_datum( |
| &self, |
| coroutine_id: CoroutineId<I>, |
| ) -> Arc<CoroutineWitnessDatum<I>> { |
| self.db.borrow().coroutine_witness_datum(coroutine_id) |
| } |
| |
| fn adt_repr(&self, id: AdtId<I>) -> Arc<AdtRepr<I>> { |
| self.db.adt_repr(id) |
| } |
| |
| fn adt_size_align(&self, id: chalk_ir::AdtId<I>) -> Arc<crate::rust_ir::AdtSizeAlign> { |
| self.db.adt_size_align(id) |
| } |
| |
| fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { |
| self.db.impl_datum(impl_id) |
| } |
| |
| fn associated_ty_value( |
| &self, |
| id: crate::rust_ir::AssociatedTyValueId<I>, |
| ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { |
| self.db.associated_ty_value(id) |
| } |
| |
| fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { |
| self.db.opaque_ty_data(id) |
| } |
| |
| fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { |
| self.db.hidden_opaque_type(id) |
| } |
| |
| fn impls_for_trait( |
| &self, |
| trait_id: TraitId<I>, |
| parameters: &[chalk_ir::GenericArg<I>], |
| binders: &CanonicalVarKinds<I>, |
| ) -> Vec<ImplId<I>> { |
| self.db.impls_for_trait(trait_id, parameters, binders) |
| } |
| |
| fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { |
| self.db.local_impls_to_coherence_check(trait_id) |
| } |
| |
| fn impl_provided_for(&self, auto_trait_id: TraitId<I>, ty: &TyKind<I>) -> bool { |
| self.db.impl_provided_for(auto_trait_id, ty) |
| } |
| |
| fn well_known_trait_id( |
| &self, |
| well_known_trait: crate::rust_ir::WellKnownTrait, |
| ) -> Option<TraitId<I>> { |
| self.db.well_known_trait_id(well_known_trait) |
| } |
| |
| fn program_clauses_for_env( |
| &self, |
| environment: &chalk_ir::Environment<I>, |
| ) -> chalk_ir::ProgramClauses<I> { |
| self.db.program_clauses_for_env(environment) |
| } |
| |
| fn interner(&self) -> I { |
| self.db.interner() |
| } |
| |
| fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { |
| self.db.is_object_safe(trait_id) |
| } |
| |
| fn unification_database(&self) -> &dyn UnificationDatabase<I> { |
| self |
| } |
| |
| fn trait_name(&self, trait_id: TraitId<I>) -> String { |
| self.db.trait_name(trait_id) |
| } |
| |
| fn adt_name(&self, adt_id: AdtId<I>) -> String { |
| self.db.adt_name(adt_id) |
| } |
| |
| fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { |
| self.db.assoc_type_name(assoc_ty_id) |
| } |
| |
| fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { |
| self.db.opaque_type_name(opaque_ty_id) |
| } |
| |
| fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { |
| self.db.fn_def_datum(fn_def_id) |
| } |
| |
| fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { |
| self.db.fn_def_name(fn_def_id) |
| } |
| |
| fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { |
| // TODO: record closure IDs |
| self.db.closure_kind(closure_id, substs) |
| } |
| |
| fn closure_inputs_and_output( |
| &self, |
| closure_id: ClosureId<I>, |
| substs: &Substitution<I>, |
| ) -> Binders<FnDefInputsAndOutputDatum<I>> { |
| self.db.closure_inputs_and_output(closure_id, substs) |
| } |
| |
| fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { |
| self.db.closure_upvars(closure_id, substs) |
| } |
| |
| fn closure_fn_substitution( |
| &self, |
| closure_id: ClosureId<I>, |
| substs: &Substitution<I>, |
| ) -> Substitution<I> { |
| self.db.closure_fn_substitution(closure_id, substs) |
| } |
| |
| fn discriminant_type(&self, ty: Ty<I>) -> Ty<I> { |
| self.db.discriminant_type(ty) |
| } |
| } |
| |
| #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
| pub enum RecordedItemId<I: Interner> { |
| Adt(AdtId<I>), |
| Trait(TraitId<I>), |
| Impl(ImplId<I>), |
| OpaqueTy(OpaqueTyId<I>), |
| FnDef(FnDefId<I>), |
| Coroutine(CoroutineId<I>), |
| } |
| |
| impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> { |
| fn from(v: AdtId<I>) -> Self { |
| RecordedItemId::Adt(v) |
| } |
| } |
| |
| impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> { |
| fn from(v: TraitId<I>) -> Self { |
| RecordedItemId::Trait(v) |
| } |
| } |
| |
| impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> { |
| fn from(v: ImplId<I>) -> Self { |
| RecordedItemId::Impl(v) |
| } |
| } |
| |
| impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> { |
| fn from(v: OpaqueTyId<I>) -> Self { |
| RecordedItemId::OpaqueTy(v) |
| } |
| } |
| |
| impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> { |
| fn from(v: FnDefId<I>) -> Self { |
| RecordedItemId::FnDef(v) |
| } |
| } |
| |
| impl<I: Interner> From<CoroutineId<I>> for RecordedItemId<I> { |
| fn from(v: CoroutineId<I>) -> Self { |
| RecordedItemId::Coroutine(v) |
| } |
| } |