1 //! Persistent state passed down between writers.
3 //! This is essentially `InternalWriterState` and other things supporting that.
8 fmt
::{Debug, Display, Formatter, Result}
,
14 use crate::RustIrDatabase
;
15 use chalk_ir
::{interner::Interner, *}
;
16 use indexmap
::IndexMap
;
17 use itertools
::Itertools
;
19 /// Like a BoundVar, but with the debrujin index inverted so as to create a
20 /// canonical name we can use anywhere for each bound variable.
22 /// In BoundVar, the innermost bound variables have debrujin index `0`, and
23 /// each further out BoundVar has a debrujin index `1` higher.
25 /// In InvertedBoundVar, the outermost variables have inverted_debrujin_idx `0`,
26 /// and the innermost have their depth, not the other way around.
27 #[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
28 pub struct InvertedBoundVar
{
29 /// The inverted debrujin index. Corresponds roughly to an inverted `DebrujinIndex::depth`.
30 inverted_debrujin_idx
: i64,
31 /// The index within the debrujin index. Corresponds to `BoundVar::index`.
32 within_idx
: IndexWithinBinding
,
35 impl Display
for InvertedBoundVar
{
36 fn fmt(&self, f
: &mut Formatter
<'_
>) -> Result
{
37 write
!(f
, "_{}_{}", self.inverted_debrujin_idx
, self.within_idx
)
41 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
42 enum UnifiedId
<I
: Interner
> {
43 AdtId(I
::InternedAdtId
),
48 pub struct IdAliasStore
<T
> {
49 /// Map from the DefIds we've encountered to a u32 alias id unique to all ids
51 aliases
: IndexMap
<T
, u32>,
52 /// Map from each name to the next unused u32 alias id.
53 next_unused_for_name
: BTreeMap
<String
, u32>,
56 impl<T
> Default
for IdAliasStore
<T
> {
57 fn default() -> Self {
59 aliases
: IndexMap
::default(),
60 next_unused_for_name
: BTreeMap
::default(),
65 impl<T
: Copy
+ Eq
+ Hash
> IdAliasStore
<T
> {
66 fn alias_for_id_name(&mut self, id
: T
, name
: String
) -> String
{
67 let next_unused_for_name
= &mut self.next_unused_for_name
;
68 let alias
= *self.aliases
.entry(id
).or_insert_with(|| {
69 let next_unused
: &mut u32 = next_unused_for_name
.entry(name
.clone()).or_default();
70 let id
= *next_unused
;
74 // If there are no conflicts, keep the name the same so that we don't
75 // need name-agnostic equality in display tests.
79 format
!("{}_{}", name
, alias
)
85 struct IdAliases
<I
: Interner
> {
86 id_aliases
: IdAliasStore
<UnifiedId
<I
>>,
89 impl<I
: Interner
> Default
for IdAliases
<I
> {
90 fn default() -> Self {
92 id_aliases
: IdAliasStore
::default(),
97 /// Writer state which persists across multiple writes.
99 /// Currently, this means keeping track of what IDs have been given what names,
100 /// including deduplication information.
102 /// This data is stored using interior mutability - clones will point to the same underlying
105 /// Uses a separate type, `P`, for the database stored inside to account for
106 /// `Arc` or wrapping other storage mediums.
108 pub struct WriterState
<I
, DB
: ?Sized
, P
= DB
>
110 DB
: RustIrDatabase
<I
>,
115 id_aliases
: Arc
<Mutex
<IdAliases
<I
>>>,
116 _phantom
: PhantomData
<DB
>,
119 impl<I
, DB
: ?Sized
, P
> Clone
for WriterState
<I
, DB
, P
>
121 DB
: RustIrDatabase
<I
>,
122 P
: Borrow
<DB
> + Clone
,
125 fn clone(&self) -> Self {
128 id_aliases
: self.id_aliases
.clone(),
129 _phantom
: PhantomData
,
134 impl<I
, DB
: ?Sized
, P
> WriterState
<I
, DB
, P
>
136 DB
: RustIrDatabase
<I
>,
140 pub fn new(db
: P
) -> Self {
143 id_aliases
: Arc
::new(Mutex
::new(IdAliases
::default())),
144 _phantom
: PhantomData
,
148 /// Returns a new version of self containing a wrapped database which
149 /// references the outer data.
151 /// `f` will be run on the internal database, and the returned result will
152 /// wrap the result from `f`. For consistency, `f` should always contain the
153 /// given database, and must keep the same ID<->item relationships.
154 pub(super) fn wrap_db_ref
<'a
, DB2
: ?Sized
, P2
, F
>(&'a
self, f
: F
) -> WriterState
<I
, DB2
, P2
>
156 DB2
: RustIrDatabase
<I
>,
158 // We need to pass in `&'a P` specifically to guarantee that the `&P`
159 // can outlive the function body, and thus that it's safe to store `&P`
161 F
: FnOnce(&'a P
) -> P2
,
165 id_aliases
: self.id_aliases
.clone(),
166 _phantom
: PhantomData
,
170 pub(crate) fn db(&self) -> &DB
{
175 /// Writer state for a single write call, persistent only as long as necessary
176 /// to write a single item.
178 /// Stores things necessary for .
179 #[derive(Clone, Debug)]
180 pub(super) struct InternalWriterState
<'a
, I
: Interner
> {
181 persistent_state
: WriterState
<I
, dyn RustIrDatabase
<I
> + 'a
, &'a
dyn RustIrDatabase
<I
>>,
183 debrujin_indices_deep
: u32,
184 // lowered_(inverted_debrujin_idx, index) -> src_correct_(inverted_debrujin_idx, index)
185 remapping
: Rc
<BTreeMap
<InvertedBoundVar
, InvertedBoundVar
>>,
186 // the inverted_bound_var which maps to "Self"
187 self_mapping
: Option
<InvertedBoundVar
>,
190 type IndexWithinBinding
= usize;
192 impl<'a
, I
: Interner
> InternalWriterState
<'a
, I
> {
193 pub fn new
<DB
, P
>(persistent_state
: &'a WriterState
<I
, DB
, P
>) -> Self
195 DB
: RustIrDatabase
<I
>,
198 InternalWriterState
{
199 persistent_state
: persistent_state
200 .wrap_db_ref(|db
| db
.borrow() as &dyn RustIrDatabase
<I
>),
202 debrujin_indices_deep
: 0,
203 remapping
: Rc
::new(BTreeMap
::new()),
208 pub(super) fn db(&self) -> &dyn RustIrDatabase
<I
> {
209 self.persistent_state
.db
212 pub(super) fn add_indent(&self) -> Self {
213 InternalWriterState
{
214 indent_level
: self.indent_level
+ 1,
219 pub(super) fn indent(&self) -> impl Display
{
220 std
::iter
::repeat(" ").take(self.indent_level
).format("")
223 pub(super) fn alias_for_adt_id_name(&self, id
: I
::InternedAdtId
, name
: String
) -> impl Display
{
224 self.persistent_state
229 .alias_for_id_name(UnifiedId
::AdtId(id
), name
)
232 pub(super) fn alias_for_id_name(&self, id
: I
::DefId
, name
: String
) -> impl Display
{
233 self.persistent_state
238 .alias_for_id_name(UnifiedId
::DefId(id
), name
)
241 /// Adds a level of debrujin index, and possibly a "Self" parameter.
243 /// This should be called whenever recursing into the value within a
246 /// If `self_binding` is `Some`, then it will introduce a new variable named
247 /// `Self` with the within-debrujin index given within and the innermost
248 /// debrujian index after increasing debrujin index.
249 #[must_use = "this returns a new `InternalWriterState`, and does not modify the existing one"]
250 pub(super) fn add_debrujin_index(&self, self_binding
: Option
<IndexWithinBinding
>) -> Self {
251 let mut new_state
= self.clone();
252 new_state
.debrujin_indices_deep
+= 1;
253 new_state
.self_mapping
= self_binding
254 .map(|idx
| new_state
.indices_for_introduced_bound_var(idx
))
255 .or(self.self_mapping
);
259 /// Adds parameter remapping.
261 /// Each of the parameters in `lowered_vars` will be mapped to its
262 /// corresponding variable in `original_vars` when printed through the
263 /// `InternalWriterState` returned from this method.
265 /// `lowered_vars` and `original_vars` must have the same length.
266 pub(super) fn add_parameter_mapping(
268 lowered_vars
: impl Iterator
<Item
= InvertedBoundVar
>,
269 original_vars
: impl Iterator
<Item
= InvertedBoundVar
>,
274 .map(|(a
, b
)| (*a
, *b
))
275 .chain(lowered_vars
.zip(original_vars
))
276 .collect
::<BTreeMap
<_
, _
>>();
278 InternalWriterState
{
279 remapping
: Rc
::new(remapping
),
284 /// Inverts the debrujin index so as to create a canonical name we can
285 /// anywhere for each bound variable.
287 /// See [`InvertedBoundVar`][InvertedBoundVar].
288 pub(super) fn invert_debrujin_idx(
291 index
: IndexWithinBinding
,
292 ) -> InvertedBoundVar
{
294 inverted_debrujin_idx
: (self.debrujin_indices_deep
as i64) - (debrujin_idx
as i64),
299 pub(super) fn apply_mappings(&self, b
: InvertedBoundVar
) -> impl Display
{
300 let remapped
= self.remapping
.get(&b
).copied().unwrap_or(b
);
301 if self.self_mapping
== Some(remapped
) {
308 pub(super) fn indices_for_bound_var(&self, b
: &BoundVar
) -> InvertedBoundVar
{
309 self.invert_debrujin_idx(b
.debruijn
.depth(), b
.index
)
312 pub(super) fn indices_for_introduced_bound_var(
314 idx
: IndexWithinBinding
,
315 ) -> InvertedBoundVar
{
316 // freshly introduced bound vars will always have debrujin index of 0,
317 // they're always "innermost".
318 self.invert_debrujin_idx(0, idx
)
321 pub(super) fn display_bound_var(&self, b
: &BoundVar
) -> impl Display
{
322 self.apply_mappings(self.indices_for_bound_var(b
))
325 pub(super) fn name_for_introduced_bound_var(&self, idx
: IndexWithinBinding
) -> impl Display
{
326 self.apply_mappings(self.indices_for_introduced_bound_var(idx
))
329 pub(super) fn binder_var_indices
<'b
>(
331 binders
: &'b VariableKinds
<I
>,
332 ) -> impl Iterator
<Item
= InvertedBoundVar
> + 'b
{
334 .iter(self.db().interner())
336 .map(move |(idx
, _param
)| self.indices_for_introduced_bound_var(idx
))
339 pub(super) fn binder_var_display
<'b
>(
341 binders
: &'b VariableKinds
<I
>,
342 ) -> impl Iterator
<Item
= String
> + 'b
{
344 .iter(self.db().interner())
345 .zip(self.binder_var_indices(binders
))
346 .map(move |(parameter
, var
)| match parameter
{
347 VariableKind
::Ty(_
) => format
!("{}", self.apply_mappings(var
)),
348 VariableKind
::Lifetime
=> format
!("'{}", self.apply_mappings(var
)),
349 VariableKind
::Const(_ty
) => format
!("const {}", self.apply_mappings(var
)),