1use crate::{
4 ast::statements::TypeAnnotation,
5 checker::structs::{CheckType, ScopeItem},
6};
7
8impl ScopeItem {
9 pub fn new(type_annotation: CheckType, is_const: bool) -> Self {
10 Self {
11 type_annotation,
12 is_const,
13 }
14 }
15}
16
17impl CheckType {
19 pub fn known(ty: TypeAnnotation) -> Self {
21 CheckType::Known(ty)
22 }
23
24 pub fn is_null(&self) -> bool {
26 matches!(self, CheckType::Known(TypeAnnotation::Null))
27 }
28
29 pub fn is_unknown(&self) -> bool {
31 matches!(self, CheckType::Unknown)
32 }
33
34 pub fn into_const(self) -> Self {
36 match self {
37 CheckType::Known(ty) => CheckType::Known(const_variant(ty)),
38 other => other,
39 }
40 }
41
42 pub fn matches(&self, expected: &CheckType) -> bool {
51 match (self, expected) {
52 (CheckType::Unknown, _) | (_, CheckType::Unknown) => true,
54
55 (CheckType::Known(TypeAnnotation::Null), _) => true,
58
59 (CheckType::Function { .. }, CheckType::Known(TypeAnnotation::Fn))
61 | (CheckType::Known(TypeAnnotation::Fn), CheckType::Function { .. }) => true,
62
63 (
66 CheckType::Function {
67 params: p1,
68 return_type: r1,
69 },
70 CheckType::Function {
71 params: p2,
72 return_type: r2,
73 },
74 ) => p1 == p2 && r1 == r2,
75
76 (CheckType::Known(a), CheckType::Known(b)) => {
78 a == b
79 || null_array_elision(a, b)
80 || null_map_elision(a, b)
81 || const_matches(a, b)
82 || record_matches(a, b)
83 || enum_matches(a, b)
84 || set_matches(a, b)
85 }
86
87 _ => false,
88 }
89 }
90
91 pub fn info(&self) -> String {
93 match self {
94 CheckType::Known(ty) => format!("{:?}", ty),
95 CheckType::Function {
96 params,
97 return_type,
98 } => format!(
99 "fn({}) -> {:?}",
100 params
101 .iter()
102 .map(|p| format!("{:?}", p))
103 .collect::<Vec<_>>()
104 .join(", "),
105 return_type
106 ),
107 CheckType::Unknown => "unknown".to_string(),
108 }
109 }
110}
111
112fn null_array_elision(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
115 match (a, b) {
116 (
117 TypeAnnotation::Array(x) | TypeAnnotation::CArray(x),
118 TypeAnnotation::Array(y) | TypeAnnotation::CArray(y),
119 ) => **x == TypeAnnotation::Null || **y == TypeAnnotation::Null || null_array_elision(x, y),
120
121 (
122 TypeAnnotation::Tuple(a) | TypeAnnotation::CTuple(a),
123 TypeAnnotation::Tuple(b) | TypeAnnotation::CTuple(b),
124 ) => a.iter().zip(b.iter()).all(|(x, y)| {
125 *x == TypeAnnotation::Null || *y == TypeAnnotation::Null || null_array_elision(x, y)
126 }),
127 _ => false,
128 }
129}
130
131fn null_map_elision(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
132 match (a, b) {
133 (
134 TypeAnnotation::Map(ak, av) | TypeAnnotation::CMap(ak, av),
135 TypeAnnotation::Map(bk, bv) | TypeAnnotation::CMap(bk, bv),
136 ) => {
137 (**ak == TypeAnnotation::Null
138 || **bk == TypeAnnotation::Null
139 || null_array_elision(ak, bk)
140 || null_map_elision(ak, bk))
141 && (**av == TypeAnnotation::Null
142 || **bv == TypeAnnotation::Null
143 || null_array_elision(av, bv)
144 || null_map_elision(av, bv))
145 }
146 _ => false,
147 }
148}
149
150fn const_variant(ty: TypeAnnotation) -> TypeAnnotation {
152 match ty {
153 TypeAnnotation::Int => TypeAnnotation::CInt,
154 TypeAnnotation::Float => TypeAnnotation::CFloat,
155 TypeAnnotation::Bool => TypeAnnotation::CBool,
156 TypeAnnotation::String => TypeAnnotation::CString,
157 TypeAnnotation::Byte => TypeAnnotation::CByte,
158 TypeAnnotation::Char => TypeAnnotation::CChar,
159 TypeAnnotation::Array(inner) => TypeAnnotation::CArray(inner),
160 TypeAnnotation::Map(key, value) => TypeAnnotation::CMap(key, value),
161 TypeAnnotation::Tuple(inner) => TypeAnnotation::CTuple(inner),
162 TypeAnnotation::Error => TypeAnnotation::CError,
163 TypeAnnotation::Result(inner) => TypeAnnotation::CResult(inner),
164 TypeAnnotation::Record(name) => TypeAnnotation::CRecord(name),
165 TypeAnnotation::Enum(name) => TypeAnnotation::CEnum(name),
166 TypeAnnotation::Set(items) => TypeAnnotation::CSet(items),
167 other => other,
168 }
169}
170
171fn record_matches(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
174 matches!(
175 (a, b),
176 (TypeAnnotation::Record(x) | TypeAnnotation::CRecord(x),
177 TypeAnnotation::Record(y) | TypeAnnotation::CRecord(y)) if x == y
178 )
179}
180
181fn enum_matches(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
184 matches!(
185 (a, b),
186 (TypeAnnotation::Enum(x) | TypeAnnotation::CEnum(x),
187 TypeAnnotation::Enum(y) | TypeAnnotation::CEnum(y)) if x == y
188 )
189}
190
191fn set_matches(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
192 matches!(
193 (a, b),
194 (TypeAnnotation::Set(x) | TypeAnnotation::CSet(x),
195 TypeAnnotation::Set(y) | TypeAnnotation::CSet(y)) if x == y
196 )
197}
198
199fn const_matches(a: &TypeAnnotation, b: &TypeAnnotation) -> bool {
201 matches!(
202 (a, b),
203 (TypeAnnotation::CString, TypeAnnotation::String)
204 | (TypeAnnotation::CInt, TypeAnnotation::Int)
205 | (TypeAnnotation::CFloat, TypeAnnotation::Float)
206 | (TypeAnnotation::CBool, TypeAnnotation::Bool)
207 | (TypeAnnotation::CByte, TypeAnnotation::Byte)
208 | (TypeAnnotation::CChar, TypeAnnotation::Char)
209 | (TypeAnnotation::CTuple(_), TypeAnnotation::Tuple(_))
210 | (TypeAnnotation::Tuple(_), TypeAnnotation::CTuple(_))
211 | (TypeAnnotation::CError, TypeAnnotation::Error)
212 | (TypeAnnotation::Error, TypeAnnotation::CError)
213 | (TypeAnnotation::CResult(_), TypeAnnotation::Result(_))
214 | (TypeAnnotation::Result(_), TypeAnnotation::CResult(_))
215 | (TypeAnnotation::CMap(_, _), TypeAnnotation::Map(_, _))
216 | (TypeAnnotation::Map(_, _), TypeAnnotation::CMap(_, _))
217 | (TypeAnnotation::Set(_), TypeAnnotation::CSet(_))
218 | (TypeAnnotation::CSet(_), TypeAnnotation::Set(_))
219 )
220}