chalk_solve/
display.rs

1use std::{
2    borrow::Borrow,
3    fmt::{Display, Result},
4    sync::Arc,
5};
6
7use crate::rust_ir::*;
8use chalk_ir::{interner::Interner, *};
9use itertools::Itertools;
10
11use crate::{logging_db::RecordedItemId, split::Split, RustIrDatabase};
12
13#[macro_use]
14mod utils;
15
16mod bounds;
17mod identifiers;
18mod items;
19mod render_trait;
20mod state;
21mod stub;
22mod ty;
23
24use self::render_trait::*;
25pub use self::state::*;
26pub use self::utils::sanitize_debug_name;
27
28use self::utils::as_display;
29
30fn write_item<F, I, T>(f: &mut F, ws: &InternalWriterState<'_, I>, v: &T) -> Result
31where
32    F: std::fmt::Write + ?Sized,
33    I: Interner,
34    T: RenderAsRust<I>,
35{
36    writeln!(f, "{}", v.display(ws))
37}
38
39/// Writes stubs for items which were referenced by name, but for which we
40/// didn't directly access. For instance, traits mentioned in where bounds which
41/// are only usually checked during well-formedness, when we weren't recording
42/// well-formedness.
43///
44/// The "stub" nature of this means it writes output with the right names and
45/// the right number of generics, but nothing else. Where clauses, bounds, and
46/// fields are skipped. Associated types are ???? skipped.
47///
48/// `RecordedItemId::Impl` is not supported.
49pub fn write_stub_items<F, I, DB, P, T>(f: &mut F, ws: &WriterState<I, DB, P>, ids: T) -> Result
50where
51    F: std::fmt::Write + ?Sized,
52    I: Interner,
53    DB: RustIrDatabase<I>,
54    P: Borrow<DB>,
55    T: IntoIterator<Item = RecordedItemId<I>>,
56{
57    let wrapped_db = &ws.wrap_db_ref(|db| stub::StubWrapper::new(db.borrow()));
58
59    write_items(f, wrapped_db, ids)
60}
61
62/// Writes out each item recorded by a [`LoggingRustIrDatabase`].
63///
64/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase
65pub fn write_items<F, I, DB, P, T>(f: &mut F, ws: &WriterState<I, DB, P>, ids: T) -> Result
66where
67    F: std::fmt::Write + ?Sized,
68    I: Interner,
69    DB: RustIrDatabase<I>,
70    P: Borrow<DB>,
71    T: IntoIterator<Item = RecordedItemId<I>>,
72{
73    for id in ids {
74        match id {
75            RecordedItemId::Impl(id) => {
76                let v = ws.db().impl_datum(id);
77                write_item(f, &InternalWriterState::new(ws), &*v)?;
78            }
79            RecordedItemId::Adt(id) => {
80                let v = ws.db().adt_datum(id);
81                write_item(f, &InternalWriterState::new(ws), &*v)?;
82            }
83            RecordedItemId::Trait(id) => {
84                let v = ws.db().trait_datum(id);
85                write_item(f, &InternalWriterState::new(ws), &*v)?;
86            }
87            RecordedItemId::OpaqueTy(id) => {
88                let v = ws.db().opaque_ty_data(id);
89                write_item(f, &InternalWriterState::new(ws), &*v)?;
90            }
91            RecordedItemId::FnDef(id) => {
92                let v = ws.db().fn_def_datum(id);
93                write_item(f, &InternalWriterState::new(ws), &*v)?;
94            }
95            RecordedItemId::Coroutine(id) => {
96                let coroutine = ws.db().coroutine_datum(id);
97                let witness = ws.db().coroutine_witness_datum(id);
98                write_item(f, &InternalWriterState::new(ws), &(&*coroutine, &*witness))?;
99            }
100        }
101    }
102    Ok(())
103}
104
105/// Displays a set of bounds, all targeting `Self`, as just the trait names,
106/// separated by `+`.
107///
108/// For example, a list of quantified where clauses which would normally be
109/// displayed as:
110///
111/// ```notrust
112/// Self: A, Self: B, Self: C
113/// ```
114///
115/// Is instead displayed by this function as:
116///
117/// ```notrust
118/// A + B + C
119/// ```
120///
121/// Shared between the `Trait` in `dyn Trait` and [`OpaqueTyDatum`] bounds.
122fn display_self_where_clauses_as_bounds<'a, I: Interner>(
123    s: &'a InternalWriterState<'a, I>,
124    bounds: &'a [QuantifiedWhereClause<I>],
125) -> impl Display + 'a {
126    as_display(move |f| {
127        let interner = s.db().interner();
128        write!(
129            f,
130            "{}",
131            bounds
132                .iter()
133                .map(|bound| {
134                    as_display(|f| {
135                        // each individual trait can have a forall
136                        let s = &s.add_debrujin_index(None);
137                        if !bound.binders.is_empty(interner) {
138                            write!(
139                                f,
140                                "forall<{}> ",
141                                s.binder_var_display(&bound.binders)
142                                    .collect::<Vec<_>>()
143                                    .join(", ")
144                            )?;
145                        }
146                        match &bound.skip_binders() {
147                            WhereClause::Implemented(trait_ref) => display_type_with_generics(
148                                s,
149                                trait_ref.trait_id,
150                                &trait_ref.substitution.as_slice(interner)[1..],
151                            )
152                            .fmt(f),
153                            WhereClause::AliasEq(alias_eq) => match &alias_eq.alias {
154                                AliasTy::Projection(projection_ty) => {
155                                    let (assoc_ty_datum, trait_params, assoc_type_params) =
156                                        s.db().split_projection(projection_ty);
157                                    display_trait_with_assoc_ty_value(
158                                        s,
159                                        assoc_ty_datum,
160                                        &trait_params[1..],
161                                        assoc_type_params,
162                                        &alias_eq.ty,
163                                    )
164                                    .fmt(f)
165                                }
166                                AliasTy::Opaque(opaque) => opaque.display(s).fmt(f),
167                            },
168                            WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f),
169                            WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f),
170                        }
171                    })
172                    .to_string()
173                })
174                .format(" + ")
175        )
176    })
177}
178
179/// Displays a type with its parameters - something like `AsRef<T>`,
180/// OpaqueTyName<U>, or `AdtName<Value>`.
181///
182/// This is shared between where bounds, OpaqueTy, & dyn Trait.
183fn display_type_with_generics<'a, I: Interner>(
184    s: &'a InternalWriterState<'a, I>,
185    trait_name: impl RenderAsRust<I> + 'a,
186    trait_params: impl IntoIterator<Item = &'a GenericArg<I>> + 'a,
187) -> impl Display + 'a {
188    use std::fmt::Write;
189    let trait_params = trait_params.into_iter().map(|param| param.display(s));
190    let mut trait_params_str = String::new();
191    write_joined_non_empty_list!(trait_params_str, "<{}>", trait_params, ", ").unwrap();
192    as_display(move |f| write!(f, "{}{}", trait_name.display(s), trait_params_str))
193}
194
195/// Displays a trait with its parameters and a single associated type -
196/// something like `IntoIterator<Item=T>`.
197///
198/// This is shared between where bounds & dyn Trait.
199fn display_trait_with_assoc_ty_value<'a, I: Interner>(
200    s: &'a InternalWriterState<'a, I>,
201    assoc_ty_datum: Arc<AssociatedTyDatum<I>>,
202    trait_params: &'a [GenericArg<I>],
203    assoc_ty_params: &'a [GenericArg<I>],
204    assoc_ty_value: &'a Ty<I>,
205) -> impl Display + 'a {
206    as_display(move |f| {
207        write!(f, "{}<", assoc_ty_datum.trait_id.display(s))?;
208        write_joined_non_empty_list!(
209            f,
210            "{}, ",
211            trait_params.iter().map(|param| param.display(s)),
212            ", "
213        )?;
214        write!(f, "{}", assoc_ty_datum.id.display(s))?;
215        write_joined_non_empty_list!(
216            f,
217            "<{}>",
218            assoc_ty_params.iter().map(|param| param.display(s)),
219            ", "
220        )?;
221        write!(f, "={}>", assoc_ty_value.display(s))?;
222        Ok(())
223    })
224}