rukalang/
meta_types.rs

1use crate::syntax::ast::TypeExpr;
2
3pub(crate) fn meta_types_compatible(expected: &TypeExpr, actual: &TypeExpr) -> bool {
4    if matches!(expected, TypeExpr::Named(name) if name == "any")
5        || matches!(actual, TypeExpr::Named(name) if name == "any")
6    {
7        return true;
8    }
9    types_equal(expected, actual)
10}
11
12fn types_equal(left: &TypeExpr, right: &TypeExpr) -> bool {
13    match (left, right) {
14        (TypeExpr::Named(left_name), TypeExpr::Tuple(items))
15            if left_name == "Unit" && items.is_empty() =>
16        {
17            true
18        }
19        (TypeExpr::Tuple(items), TypeExpr::Named(right_name))
20            if items.is_empty() && right_name == "Unit" =>
21        {
22            true
23        }
24        (TypeExpr::Named(left_name), TypeExpr::Named(right_name)) => left_name == right_name,
25        (TypeExpr::Pointer { item: left_item }, TypeExpr::Pointer { item: right_item }) => {
26            types_equal(left_item, right_item)
27        }
28        (
29            TypeExpr::Array {
30                item: left_item,
31                len: left_len,
32            },
33            TypeExpr::Array {
34                item: right_item,
35                len: right_len,
36            },
37        ) => left_len == right_len && types_equal(left_item, right_item),
38        (TypeExpr::Slice { item: left_item }, TypeExpr::Slice { item: right_item }) => {
39            types_equal(left_item, right_item)
40        }
41        (TypeExpr::Tuple(left_items), TypeExpr::Tuple(right_items)) => {
42            left_items.len() == right_items.len()
43                && left_items
44                    .iter()
45                    .zip(right_items)
46                    .all(|(left_item, right_item)| types_equal(left_item, right_item))
47        }
48        (
49            TypeExpr::Apply {
50                callee: left_callee,
51                args: left_args,
52            },
53            TypeExpr::Apply {
54                callee: right_callee,
55                args: right_args,
56            },
57        ) => {
58            left_callee == right_callee
59                && left_args.len() == right_args.len()
60                && left_args
61                    .iter()
62                    .zip(right_args)
63                    .all(|(left_arg, right_arg)| types_equal(left_arg, right_arg))
64        }
65        _ => left == right,
66    }
67}
68
69pub(crate) fn format_type_expr(ty: &TypeExpr) -> String {
70    match ty {
71        TypeExpr::TypeKind => "type".to_owned(),
72        TypeExpr::Named(name) => name.clone(),
73        TypeExpr::Pointer { item } => format!("*{}", format_type_expr(item)),
74        TypeExpr::Array { item, len } => format!("[{}; {}]", format_type_expr(item), len),
75        TypeExpr::Slice { item } => format!("[{}]", format_type_expr(item)),
76        TypeExpr::Tuple(items) => {
77            let parts = items
78                .iter()
79                .map(format_type_expr)
80                .collect::<Vec<_>>()
81                .join(", ");
82            format!("Tuple[{parts}]")
83        }
84        TypeExpr::Apply { callee, args } => {
85            let parts = args
86                .iter()
87                .map(format_type_expr)
88                .collect::<Vec<_>>()
89                .join(", ");
90            format!("{callee}[{parts}]")
91        }
92        TypeExpr::Struct { .. } => "struct {...}".to_owned(),
93        TypeExpr::Enum { .. } => "enum {...}".to_owned(),
94        TypeExpr::Union { .. } => "union {...}".to_owned(),
95    }
96}
97
98pub(crate) fn tuple_head_type(ty: &TypeExpr) -> Option<TypeExpr> {
99    match ty {
100        TypeExpr::Tuple(items) => items.first().cloned(),
101        TypeExpr::Named(name) if name == "Unit" => None,
102        _ => None,
103    }
104}
105
106pub(crate) fn tuple_tail_type(ty: &TypeExpr) -> Option<TypeExpr> {
107    match ty {
108        TypeExpr::Tuple(items) if items.len() <= 1 => Some(TypeExpr::Tuple(Vec::new())),
109        TypeExpr::Tuple(items) => Some(TypeExpr::Tuple(items[1..].to_vec())),
110        TypeExpr::Named(name) if name == "Unit" => Some(TypeExpr::Tuple(Vec::new())),
111        _ => None,
112    }
113}