Skip to main content

charon_lib/transform/add_missing_info/
compute_short_names.rs

1use std::collections::{HashMap, hash_map::Entry};
2
3use crate::ast::*;
4
5use crate::transform::{TransformCtx, ctx::TransformPass};
6
7enum FoundName<'a> {
8    Unique {
9        long: &'a [PathElem],
10        ids: Vec<ItemId>,
11    },
12    Multiple,
13}
14
15fn register_short_name_candidate<'a>(
16    short_names: &mut HashMap<String, FoundName<'a>>,
17    short: String,
18    long: &'a [PathElem],
19    id: ItemId,
20) {
21    match short_names.entry(short) {
22        Entry::Occupied(mut e) => match e.get_mut() {
23            FoundName::Unique {
24                long: found_long,
25                ids,
26            } => {
27                if *found_long == long {
28                    ids.push(id)
29                } else {
30                    e.insert(FoundName::Multiple);
31                }
32            }
33            FoundName::Multiple => {}
34        },
35        Entry::Vacant(e) => {
36            e.insert(FoundName::Unique {
37                long,
38                ids: vec![id],
39            });
40        }
41    }
42}
43
44pub struct Transform;
45impl TransformPass for Transform {
46    fn transform_ctx(&self, ctx: &mut TransformCtx) {
47        ctx.translated.short_names.clear();
48        let mut short_names: HashMap<String, FoundName> = Default::default();
49        for (&id, name) in &ctx.translated.item_names {
50            let mut name_slice = name.name.as_slice();
51
52            // Trait impls are sufficiently unique information, so truncate starting from the
53            // rightmost impl.
54            if let Some((i, _)) = name_slice
55                .iter()
56                .enumerate()
57                .rfind(|(_, elem)| matches!(elem, PathElem::Impl(ImplElem::Trait(..), ..)))
58            {
59                name_slice = &name.name[i..];
60                let trunc_name = Name {
61                    name: name_slice.to_vec(),
62                };
63                ctx.translated.short_names.insert(id, trunc_name);
64            }
65
66            if let [prefix @ .., PathElem::Instantiated(..)] = name_slice {
67                name_slice = prefix;
68            }
69            // Ignoring monomorphizations, if a name is the only one to end with a given suffix, we
70            // accumulate the ids of all the items with that name (there may be several thanks to
71            // monomorphizations).
72            let candidate = match name_slice {
73                [.., PathElem::Ident(ident, _)] => Some(ident.clone()),
74                [PathElem::Impl(ImplElem::Trait(impl_id))]
75                    if let Some(trait_impl) = ctx.translated.trait_impls.get(*impl_id) =>
76                {
77                    trait_impl_short_name(&ctx.translated.item_names, trait_impl)
78                }
79
80                _ => None,
81            };
82            if let Some(short) = candidate {
83                register_short_name_candidate(&mut short_names, short, name_slice, id);
84            }
85        }
86
87        for (short, found) in short_names {
88            if let FoundName::Unique { ids, .. } = found {
89                for id in ids {
90                    let mut short_name = Name {
91                        name: vec![PathElem::Ident(short.clone(), Disambiguator::ZERO)],
92                    };
93                    if let [.., mono @ PathElem::Instantiated(..)] =
94                        ctx.translated.item_names[&id].name.as_slice()
95                    {
96                        short_name.name.push(mono.clone());
97                    }
98                    ctx.translated.short_names.insert(id, short_name);
99                }
100            }
101        }
102    }
103}
104
105fn trait_impl_short_name(
106    item_names: &SeqHashMap<ItemId, Name>,
107    trait_impl: &TraitImpl,
108) -> Option<String> {
109    fn args_to_idents(
110        item_names: &SeqHashMap<ItemId, Name>,
111        generics: &GenericArgs,
112    ) -> Vec<String> {
113        generics
114            .types
115            .iter()
116            .filter_map(|t| ty_to_idents(item_names, t))
117            .collect()
118    }
119
120    fn ty_to_idents(item_names: &SeqHashMap<ItemId, Name>, ty: &Ty) -> Option<String> {
121        Some(match ty.kind() {
122            TyKind::Literal(literal) => literal.to_string(),
123            TyKind::Slice(..) => "slice".to_owned(),
124            TyKind::Array(..) => "array".to_owned(),
125            TyKind::Adt(tref) => match tref.id {
126                TypeId::Adt(id) => item_to_ident(item_names, ItemId::Type(id))?,
127                TypeId::Builtin(builtin) => builtin.get_name().short_str()?.to_owned(),
128                TypeId::Tuple if tref.generics.types.is_empty() => "unit".to_owned(),
129                TypeId::Tuple => "tuple".to_owned(),
130            },
131            _ => return None,
132        })
133    }
134
135    fn item_to_ident(item_names: &SeqHashMap<ItemId, Name>, id: ItemId) -> Option<String> {
136        Some(item_names.get(&id)?.short_str()?.to_owned())
137    }
138
139    let trait_id = trait_impl.impl_trait.id;
140    let (self_ty, partial_trait_ref) = trait_impl.impl_trait.split_self();
141    let self_ty = self_ty.as_ref()?;
142
143    let mut candidate = vec!["impl".to_owned()];
144    candidate.push(item_to_ident(item_names, trait_id.into())?);
145    candidate.extend(args_to_idents(item_names, &partial_trait_ref.generics));
146    candidate.push("for".to_owned());
147    candidate.push(if let TyKind::TypeVar(_) = self_ty.kind() {
148        "T".to_string()
149    } else {
150        ty_to_idents(item_names, self_ty)?
151    });
152    if let TyKind::Adt(tref) = self_ty.kind() {
153        candidate.extend(args_to_idents(item_names, &tref.generics));
154    };
155    Some(candidate.join("_"))
156}