rue_types/
stringify.rs

1use id_arena::Arena;
2use indexmap::IndexMap;
3
4use crate::{Type, TypeId, substitute};
5
6pub fn stringify(arena: &mut Arena<Type>, id: TypeId) -> String {
7    let id = substitute(arena, id);
8    stringify_impl(arena, id, &mut IndexMap::new())
9}
10
11pub(crate) fn stringify_impl(
12    arena: &Arena<Type>,
13    id: TypeId,
14    stack: &mut IndexMap<TypeId, bool>,
15) -> String {
16    let len = stack.len();
17
18    if stack.contains_key(&id) {
19        stack.insert(id, true);
20        return format!("<{}>", stack.get_index_of(&id).unwrap());
21    }
22
23    stack.insert(id, false);
24
25    let result = match arena[id].clone() {
26        Type::Ref(id) => stringify_impl(arena, id, stack),
27        Type::Unresolved => "{unresolved}".to_string(),
28        Type::Generic => format!("{{generic {}}}", id.index()),
29        Type::Never => "Never".to_string(),
30        Type::Atom(atom) => atom.to_string(),
31        Type::Pair(pair) => {
32            let first = stringify_impl(arena, pair.first, stack);
33            let rest = stringify_impl(arena, pair.rest, stack);
34            format!("({first}, {rest})")
35        }
36        Type::Struct(ty) => {
37            if let Some(name) = ty.name {
38                name.text().to_string()
39            } else {
40                stringify_impl(arena, ty.inner, stack)
41            }
42        }
43        Type::Alias(alias) => {
44            if let Some(name) = alias.name {
45                name.text().to_string()
46            } else {
47                stringify_impl(arena, alias.inner, stack)
48            }
49        }
50        Type::Apply(apply) => {
51            let inner = stringify_impl(arena, apply.inner, stack);
52            let generics = apply
53                .generics
54                .iter()
55                .map(|(k, v)| {
56                    format!(
57                        "{}: {}",
58                        stringify_impl(arena, *k, stack),
59                        stringify_impl(arena, *v, stack)
60                    )
61                })
62                .collect::<Vec<_>>()
63                .join(", ");
64            format!("{inner}<{generics}>")
65        }
66        Type::Function(function) => {
67            let params = function
68                .params
69                .iter()
70                .map(|id| stringify_impl(arena, *id, stack))
71                .collect::<Vec<_>>()
72                .join(", ");
73            let ret = stringify_impl(arena, function.ret, stack);
74            format!("fn({params}) -> {ret}")
75        }
76        Type::Union(union) => union
77            .types
78            .iter()
79            .map(|id| stringify_impl(arena, *id, stack))
80            .collect::<Vec<_>>()
81            .join(" | "),
82    };
83
84    let recursed = stack.pop().unwrap().1;
85
86    if recursed {
87        if result.starts_with('(') {
88            format!("{len} @ {result}")
89        } else {
90            format!("{len} @ ({result})")
91        }
92    } else {
93        result
94    }
95}