use std::{ borrow::Borrow, fmt::{Display, Result}, sync::Arc, }; use crate::rust_ir::*; use chalk_ir::{interner::Interner, *}; use itertools::Itertools; use crate::{logging_db::RecordedItemId, split::Split, RustIrDatabase}; #[macro_use] mod utils; mod bounds; mod identifiers; mod items; mod render_trait; mod state; mod stub; mod ty; use self::render_trait::*; pub use self::state::*; pub use self::utils::sanitize_debug_name; use self::utils::as_display; fn write_item(f: &mut F, ws: &InternalWriterState<'_, I>, v: &T) -> Result where F: std::fmt::Write + ?Sized, I: Interner, T: RenderAsRust, { writeln!(f, "{}", v.display(ws)) } /// Writes stubs for items which were referenced by name, but for which we /// didn't directly access. For instance, traits mentioned in where bounds which /// are only usually checked during well-formedness, when we weren't recording /// well-formedness. /// /// The "stub" nature of this means it writes output with the right names and /// the right number of generics, but nothing else. Where clauses, bounds, and /// fields are skipped. Associated types are ???? skipped. /// /// `RecordedItemId::Impl` is not supported. pub fn write_stub_items(f: &mut F, ws: &WriterState, ids: T) -> Result where F: std::fmt::Write + ?Sized, I: Interner, DB: RustIrDatabase, P: Borrow, T: IntoIterator>, { let wrapped_db = &ws.wrap_db_ref(|db| stub::StubWrapper::new(db.borrow())); write_items(f, wrapped_db, ids) } /// Writes out each item recorded by a [`LoggingRustIrDatabase`]. /// /// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase pub fn write_items(f: &mut F, ws: &WriterState, ids: T) -> Result where F: std::fmt::Write + ?Sized, I: Interner, DB: RustIrDatabase, P: Borrow, T: IntoIterator>, { for id in ids { match id { RecordedItemId::Impl(id) => { let v = ws.db().impl_datum(id); write_item(f, &InternalWriterState::new(ws), &*v)?; } RecordedItemId::Adt(id) => { let v = ws.db().adt_datum(id); write_item(f, &InternalWriterState::new(ws), &*v)?; } RecordedItemId::Trait(id) => { let v = ws.db().trait_datum(id); write_item(f, &InternalWriterState::new(ws), &*v)?; } RecordedItemId::OpaqueTy(id) => { let v = ws.db().opaque_ty_data(id); write_item(f, &InternalWriterState::new(ws), &*v)?; } RecordedItemId::FnDef(id) => { let v = ws.db().fn_def_datum(id); write_item(f, &InternalWriterState::new(ws), &*v)?; } RecordedItemId::Generator(id) => { let generator = ws.db().generator_datum(id); let witness = ws.db().generator_witness_datum(id); write_item(f, &InternalWriterState::new(ws), &(&*generator, &*witness))?; } } } Ok(()) } /// Displays a set of bounds, all targeting `Self`, as just the trait names, /// separated by `+`. /// /// For example, a list of quantified where clauses which would normally be /// displayed as: /// /// ```notrust /// Self: A, Self: B, Self: C /// ``` /// /// Is instead displayed by this function as: /// /// ```notrust /// A + B + C /// ``` /// /// Shared between the `Trait` in `dyn Trait` and [`OpaqueTyDatum`] bounds. fn display_self_where_clauses_as_bounds<'a, I: Interner>( s: &'a InternalWriterState<'a, I>, bounds: &'a [QuantifiedWhereClause], ) -> impl Display + 'a { as_display(move |f| { let interner = s.db().interner(); write!( f, "{}", bounds .iter() .map(|bound| { as_display(|f| { // each individual trait can have a forall let s = &s.add_debrujin_index(None); if !bound.binders.is_empty(interner) { write!( f, "forall<{}> ", s.binder_var_display(&bound.binders) .collect::>() .join(", ") )?; } match &bound.skip_binders() { WhereClause::Implemented(trait_ref) => display_type_with_generics( s, trait_ref.trait_id, &trait_ref.substitution.as_slice(interner)[1..], ) .fmt(f), WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { AliasTy::Projection(projection_ty) => { let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(projection_ty); display_trait_with_assoc_ty_value( s, assoc_ty_datum, &trait_params[1..], assoc_type_params, &alias_eq.ty, ) .fmt(f) } AliasTy::Opaque(opaque) => opaque.display(s).fmt(f), }, WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), } }) .to_string() }) .format(" + ") ) }) } /// Displays a type with its parameters - something like `AsRef`, /// OpaqueTyName, or `AdtName`. /// /// This is shared between where bounds, OpaqueTy, & dyn Trait. fn display_type_with_generics<'a, I: Interner>( s: &'a InternalWriterState<'a, I>, trait_name: impl RenderAsRust + 'a, trait_params: impl IntoIterator> + 'a, ) -> impl Display + 'a { use std::fmt::Write; let trait_params = trait_params.into_iter().map(|param| param.display(s)); let mut trait_params_str = String::new(); write_joined_non_empty_list!(trait_params_str, "<{}>", trait_params, ", ").unwrap(); as_display(move |f| write!(f, "{}{}", trait_name.display(s), trait_params_str)) } /// Displays a trait with its parameters and a single associated type - /// something like `IntoIterator`. /// /// This is shared between where bounds & dyn Trait. fn display_trait_with_assoc_ty_value<'a, I: Interner>( s: &'a InternalWriterState<'a, I>, assoc_ty_datum: Arc>, trait_params: &'a [GenericArg], assoc_ty_params: &'a [GenericArg], assoc_ty_value: &'a Ty, ) -> impl Display + 'a { as_display(move |f| { write!(f, "{}<", assoc_ty_datum.trait_id.display(s))?; write_joined_non_empty_list!( f, "{}, ", trait_params.iter().map(|param| param.display(s)), ", " )?; write!(f, "{}", assoc_ty_datum.id.display(s))?; write_joined_non_empty_list!( f, "<{}>", assoc_ty_params.iter().map(|param| param.display(s)), ", " )?; write!(f, "={}>", assoc_ty_value.display(s))?; Ok(()) }) }