charon_lib/transform/
lift_associated_item_clauses.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//! Move clauses on associated types to be parent clauses. The distinction is not semantically
//! meaningful. We should ideally to this directly when translating but this is currently
//! difficult; instead we do this as a post-processing pass.
use std::collections::HashMap;
use std::mem;

use derive_visitor::{visitor_enter_fn_mut, DriveMut};

use crate::{ast::*, ids::Vector};

use super::{ctx::TransformPass, TransformCtx};

pub struct Transform;
impl TransformPass for Transform {
    fn transform_ctx(&self, ctx: &mut TransformCtx<'_>) {
        // For each trait, we move the item-local clauses to be top-level parent clauses, and
        // record the mapping from the old to the new ids.
        let trait_item_clause_ids: Vector<
            TraitDeclId,
            HashMap<TraitItemName, Vector<TraitClauseId, TraitClauseId>>,
        > = ctx.translated.trait_decls.map_ref_mut(|decl| {
            mem::take(&mut decl.type_clauses)
                .into_iter()
                .map(|(name, clauses)| {
                    let id_map = clauses.map(|mut clause| {
                        decl.parent_clauses.push_with(|id| {
                            clause.clause_id = id;
                            clause
                        })
                    });
                    (name, id_map)
                })
                .collect()
        });

        // Move the item-local trait refs to match what we did in the trait declarations.
        for timpl in ctx.translated.trait_impls.iter_mut() {
            for (_, refs) in mem::take(&mut timpl.type_clauses) {
                for trait_ref in refs {
                    // Note: this assumes that we listed the types in the same order as in the trait
                    // decl, which we do.
                    timpl.parent_trait_refs.push(trait_ref);
                }
            }
        }

        // Update trait refs.
        ctx.translated
            .drive_mut(&mut Ty::visit_inside_stateless(visitor_enter_fn_mut(
                |trkind: &mut TraitRefKind| {
                    use TraitRefKind::*;
                    if let ItemClause(..) = trkind {
                        take_mut::take(trkind, |trkind| {
                            let ItemClause(trait_ref, trait_decl, item_name, item_clause_id) =
                                trkind
                            else {
                                unreachable!()
                            };
                            let new_id = (|| {
                                let new_id = *trait_item_clause_ids
                                    .get(trait_decl)?
                                    .get(&item_name)?
                                    .get(item_clause_id)?;
                                Some(new_id)
                            })();
                            match new_id {
                                Some(new_id) => ParentClause(trait_ref, trait_decl, new_id),
                                None => {
                                    ItemClause(trait_ref, trait_decl, item_name, item_clause_id)
                                }
                            }
                        })
                    }
                },
            )));
    }
}