1use std::sync::Arc;
2
3use indexmap::IndexMap;
4use serde::{Deserialize, Serialize};
5
6use crate::Union;
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct FnParam {
14 pub name: Arc<str>,
15 pub ty: Option<Union>,
16 pub default: Option<Union>,
17 pub is_variadic: bool,
18 pub is_byref: bool,
19 pub is_optional: bool,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
27pub enum Variance {
28 #[default]
30 Invariant,
31 Covariant,
33 Contravariant,
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct TemplateParam {
43 pub name: Arc<str>,
44 pub bound: Option<Union>,
45 pub variance: Variance,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
53pub enum ArrayKey {
54 String(Arc<str>),
55 Int(i64),
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
59pub struct KeyedProperty {
60 pub ty: Union,
61 pub optional: bool,
62}
63
64#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
69pub enum Atomic {
70 TString,
73 TLiteralString(Arc<str>),
75 TClassString(Option<Arc<str>>),
77 TNonEmptyString,
79 TNumericString,
81
82 TInt,
84 TLiteralInt(i64),
86 TIntRange { min: Option<i64>, max: Option<i64> },
88 TPositiveInt,
90 TNegativeInt,
92 TNonNegativeInt,
94
95 TFloat,
97 TLiteralFloat(i64, i64), TBool,
102 TTrue,
104 TFalse,
106
107 TNull,
109
110 TVoid,
113 TNever,
115 TMixed,
117 TScalar,
119 TNumeric,
121
122 TObject,
125 TNamedObject {
127 fqcn: Arc<str>,
128 type_params: Vec<Union>,
130 },
131 TStaticObject { fqcn: Arc<str> },
133 TSelf { fqcn: Arc<str> },
135 TParent { fqcn: Arc<str> },
137
138 TCallable {
141 params: Option<Vec<FnParam>>,
142 return_type: Option<Box<Union>>,
143 },
144 TClosure {
146 params: Vec<FnParam>,
147 return_type: Box<Union>,
148 this_type: Option<Box<Union>>,
149 },
150
151 TArray { key: Box<Union>, value: Box<Union> },
154 TList { value: Box<Union> },
156 TNonEmptyArray { key: Box<Union>, value: Box<Union> },
158 TNonEmptyList { value: Box<Union> },
160 TKeyedArray {
162 properties: IndexMap<ArrayKey, KeyedProperty>,
163 is_open: bool,
165 is_list: bool,
167 },
168
169 TTemplateParam {
172 name: Arc<str>,
173 as_type: Box<Union>,
174 defining_entity: Arc<str>,
176 },
177 TConditional {
179 subject: Box<Union>,
180 if_true: Box<Union>,
181 if_false: Box<Union>,
182 },
183
184 TInterfaceString,
187 TEnumString,
189 TTraitString,
191
192 TIntersection { parts: Vec<Union> },
195}
196
197impl Atomic {
198 pub fn can_be_falsy(&self) -> bool {
200 match self {
201 Atomic::TNull
202 | Atomic::TFalse
203 | Atomic::TBool
204 | Atomic::TNever
205 | Atomic::TLiteralInt(0)
206 | Atomic::TLiteralFloat(0, 0)
207 | Atomic::TInt
208 | Atomic::TFloat
209 | Atomic::TNumeric
210 | Atomic::TScalar
211 | Atomic::TMixed
212 | Atomic::TString
213 | Atomic::TNonEmptyString
214 | Atomic::TArray { .. }
215 | Atomic::TList { .. }
216 | Atomic::TNonEmptyArray { .. }
217 | Atomic::TNonEmptyList { .. } => true,
218
219 Atomic::TLiteralString(s) => s.as_ref().is_empty() || s.as_ref() == "0",
220
221 Atomic::TKeyedArray { properties, .. } => properties.is_empty(),
222
223 _ => false,
224 }
225 }
226
227 pub fn can_be_truthy(&self) -> bool {
229 match self {
230 Atomic::TNever | Atomic::TVoid => false,
231 Atomic::TNull | Atomic::TFalse => false,
232 Atomic::TLiteralInt(0) => false,
233 Atomic::TLiteralFloat(0, 0) => false,
234 Atomic::TLiteralString(s) if s.as_ref() == "" || s.as_ref() == "0" => false,
235 _ => true,
236 }
237 }
238
239 pub fn is_numeric(&self) -> bool {
241 matches!(
242 self,
243 Atomic::TInt
244 | Atomic::TLiteralInt(_)
245 | Atomic::TIntRange { .. }
246 | Atomic::TPositiveInt
247 | Atomic::TNegativeInt
248 | Atomic::TNonNegativeInt
249 | Atomic::TFloat
250 | Atomic::TLiteralFloat(..)
251 | Atomic::TNumeric
252 | Atomic::TNumericString
253 )
254 }
255
256 pub fn is_int(&self) -> bool {
258 matches!(
259 self,
260 Atomic::TInt
261 | Atomic::TLiteralInt(_)
262 | Atomic::TIntRange { .. }
263 | Atomic::TPositiveInt
264 | Atomic::TNegativeInt
265 | Atomic::TNonNegativeInt
266 )
267 }
268
269 pub fn is_string(&self) -> bool {
271 matches!(
272 self,
273 Atomic::TString
274 | Atomic::TLiteralString(_)
275 | Atomic::TClassString(_)
276 | Atomic::TNonEmptyString
277 | Atomic::TNumericString
278 | Atomic::TInterfaceString
279 | Atomic::TEnumString
280 | Atomic::TTraitString
281 )
282 }
283
284 pub fn is_array(&self) -> bool {
286 matches!(
287 self,
288 Atomic::TArray { .. }
289 | Atomic::TList { .. }
290 | Atomic::TNonEmptyArray { .. }
291 | Atomic::TNonEmptyList { .. }
292 | Atomic::TKeyedArray { .. }
293 )
294 }
295
296 pub fn is_object(&self) -> bool {
298 matches!(
299 self,
300 Atomic::TObject
301 | Atomic::TNamedObject { .. }
302 | Atomic::TStaticObject { .. }
303 | Atomic::TSelf { .. }
304 | Atomic::TParent { .. }
305 | Atomic::TIntersection { .. }
306 )
307 }
308
309 pub fn is_callable(&self) -> bool {
311 matches!(self, Atomic::TCallable { .. } | Atomic::TClosure { .. })
312 }
313
314 pub fn named_object_fqcn(&self) -> Option<&str> {
316 match self {
317 Atomic::TNamedObject { fqcn, .. }
318 | Atomic::TStaticObject { fqcn }
319 | Atomic::TSelf { fqcn }
320 | Atomic::TParent { fqcn } => Some(fqcn.as_ref()),
321 _ => None,
322 }
323 }
324
325 pub fn type_name(&self) -> &'static str {
327 match self {
328 Atomic::TString
329 | Atomic::TLiteralString(_)
330 | Atomic::TNonEmptyString
331 | Atomic::TNumericString => "string",
332 Atomic::TClassString(_) => "class-string",
333 Atomic::TInt | Atomic::TLiteralInt(_) | Atomic::TIntRange { .. } => "int",
334 Atomic::TPositiveInt => "positive-int",
335 Atomic::TNegativeInt => "negative-int",
336 Atomic::TNonNegativeInt => "non-negative-int",
337 Atomic::TFloat | Atomic::TLiteralFloat(..) => "float",
338 Atomic::TBool => "bool",
339 Atomic::TTrue => "true",
340 Atomic::TFalse => "false",
341 Atomic::TNull => "null",
342 Atomic::TVoid => "void",
343 Atomic::TNever => "never",
344 Atomic::TMixed => "mixed",
345 Atomic::TScalar => "scalar",
346 Atomic::TNumeric => "numeric",
347 Atomic::TObject => "object",
348 Atomic::TNamedObject { .. } => "object",
349 Atomic::TStaticObject { .. } => "static",
350 Atomic::TSelf { .. } => "self",
351 Atomic::TParent { .. } => "parent",
352 Atomic::TCallable { .. } => "callable",
353 Atomic::TClosure { .. } => "Closure",
354 Atomic::TArray { .. } => "array",
355 Atomic::TList { .. } => "list",
356 Atomic::TNonEmptyArray { .. } => "non-empty-array",
357 Atomic::TNonEmptyList { .. } => "non-empty-list",
358 Atomic::TKeyedArray { .. } => "array",
359 Atomic::TTemplateParam { .. } => "template-param",
360 Atomic::TConditional { .. } => "conditional-type",
361 Atomic::TInterfaceString => "interface-string",
362 Atomic::TEnumString => "enum-string",
363 Atomic::TTraitString => "trait-string",
364 Atomic::TIntersection { .. } => "intersection",
365 }
366 }
367}