charon_lib/transform/
lift_associated_item_clauses.rs

1//! Move clauses on associated types to be parent clauses. The distinction is not semantically
2//! meaningful. We should ideally to this directly when translating but this is currently
3//! difficult; instead we do this as a post-processing pass.
4use std::collections::HashMap;
5use std::mem;
6
7use crate::{ast::*, ids::Vector};
8
9use super::{TransformCtx, ctx::TransformPass};
10
11pub struct Transform;
12impl TransformPass for Transform {
13    fn transform_ctx(&self, ctx: &mut TransformCtx) {
14        // For each trait, we move the item-local clauses to be top-level parent clauses, and
15        // record the mapping from the old to the new ids.
16        let trait_item_clause_ids: Vector<
17            TraitDeclId,
18            HashMap<TraitItemName, Vector<TraitClauseId, TraitClauseId>>,
19        > = ctx.translated.trait_decls.map_ref_mut(|decl| {
20            mem::take(&mut decl.type_clauses)
21                .into_iter()
22                .map(|(name, clauses)| {
23                    let id_map = clauses.map(|mut clause| {
24                        decl.parent_clauses.push_with(|id| {
25                            clause.clause_id = id;
26                            clause
27                        })
28                    });
29                    (name, id_map)
30                })
31                .collect()
32        });
33
34        // Move the item-local trait refs to match what we did in the trait declarations.
35        for timpl in ctx.translated.trait_impls.iter_mut() {
36            for (_, refs) in mem::take(&mut timpl.type_clauses) {
37                for trait_ref in refs {
38                    // Note: this assumes that we listed the types in the same order as in the trait
39                    // decl, which we do.
40                    timpl.parent_trait_refs.push(trait_ref);
41                }
42            }
43        }
44
45        // Update trait refs.
46        ctx.translated.dyn_visit_mut(|trkind: &mut TraitRefKind| {
47            use TraitRefKind::*;
48            match trkind {
49                ItemClause(..) => take_mut::take(trkind, |trkind| {
50                    let ItemClause(tref, item_name, item_clause_id) = trkind else {
51                        unreachable!()
52                    };
53                    let new_id = (|| {
54                        let new_id = *trait_item_clause_ids
55                            .get(tref.trait_decl_ref.skip_binder.id)?
56                            .get(&item_name)?
57                            .get(item_clause_id)?;
58                        Some(new_id)
59                    })();
60                    match new_id {
61                        Some(new_id) => ParentClause(tref, new_id),
62                        None => ItemClause(tref, item_name, item_clause_id),
63                    }
64                }),
65                BuiltinOrAuto {
66                    parent_trait_refs,
67                    types,
68                    ..
69                } => {
70                    for (_, _, ty_trait_refs) in types {
71                        for tref in std::mem::take(ty_trait_refs) {
72                            // Note: this assumes that we listed the types in the same order as in
73                            // the trait decl, which we do.
74                            parent_trait_refs.push(tref);
75                        }
76                    }
77                }
78                _ => {}
79            }
80        });
81    }
82}