Skip to main content

charon_lib/transform/add_missing_info/
compute_short_names.rs

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