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}