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
231 | Atomic::TVoid
232 | Atomic::TNull
233 | Atomic::TFalse
234 | Atomic::TLiteralInt(0)
235 | Atomic::TLiteralFloat(0, 0) => false,
236 Atomic::TLiteralString(s) if s.as_ref() == "" || s.as_ref() == "0" => false,
237 _ => true,
238 }
239 }
240
241 pub fn is_numeric(&self) -> bool {
243 matches!(
244 self,
245 Atomic::TInt
246 | Atomic::TLiteralInt(_)
247 | Atomic::TIntRange { .. }
248 | Atomic::TPositiveInt
249 | Atomic::TNegativeInt
250 | Atomic::TNonNegativeInt
251 | Atomic::TFloat
252 | Atomic::TLiteralFloat(..)
253 | Atomic::TNumeric
254 | Atomic::TNumericString
255 )
256 }
257
258 pub fn is_int(&self) -> bool {
260 matches!(
261 self,
262 Atomic::TInt
263 | Atomic::TLiteralInt(_)
264 | Atomic::TIntRange { .. }
265 | Atomic::TPositiveInt
266 | Atomic::TNegativeInt
267 | Atomic::TNonNegativeInt
268 )
269 }
270
271 pub fn is_string(&self) -> bool {
273 matches!(
274 self,
275 Atomic::TString
276 | Atomic::TLiteralString(_)
277 | Atomic::TClassString(_)
278 | Atomic::TNonEmptyString
279 | Atomic::TNumericString
280 | Atomic::TInterfaceString
281 | Atomic::TEnumString
282 | Atomic::TTraitString
283 )
284 }
285
286 pub fn is_array(&self) -> bool {
288 matches!(
289 self,
290 Atomic::TArray { .. }
291 | Atomic::TList { .. }
292 | Atomic::TNonEmptyArray { .. }
293 | Atomic::TNonEmptyList { .. }
294 | Atomic::TKeyedArray { .. }
295 )
296 }
297
298 pub fn is_object(&self) -> bool {
300 matches!(
301 self,
302 Atomic::TObject
303 | Atomic::TNamedObject { .. }
304 | Atomic::TStaticObject { .. }
305 | Atomic::TSelf { .. }
306 | Atomic::TParent { .. }
307 | Atomic::TIntersection { .. }
308 )
309 }
310
311 pub fn is_callable(&self) -> bool {
313 matches!(self, Atomic::TCallable { .. } | Atomic::TClosure { .. })
314 }
315
316 pub fn named_object_fqcn(&self) -> Option<&str> {
318 match self {
319 Atomic::TNamedObject { fqcn, .. }
320 | Atomic::TStaticObject { fqcn }
321 | Atomic::TSelf { fqcn }
322 | Atomic::TParent { fqcn } => Some(fqcn.as_ref()),
323 _ => None,
324 }
325 }
326
327 pub fn type_name(&self) -> &'static str {
329 match self {
330 Atomic::TString
331 | Atomic::TLiteralString(_)
332 | Atomic::TNonEmptyString
333 | Atomic::TNumericString => "string",
334 Atomic::TClassString(_) => "class-string",
335 Atomic::TInt | Atomic::TLiteralInt(_) | Atomic::TIntRange { .. } => "int",
336 Atomic::TPositiveInt => "positive-int",
337 Atomic::TNegativeInt => "negative-int",
338 Atomic::TNonNegativeInt => "non-negative-int",
339 Atomic::TFloat | Atomic::TLiteralFloat(..) => "float",
340 Atomic::TBool => "bool",
341 Atomic::TTrue => "true",
342 Atomic::TFalse => "false",
343 Atomic::TNull => "null",
344 Atomic::TVoid => "void",
345 Atomic::TNever => "never",
346 Atomic::TMixed => "mixed",
347 Atomic::TScalar => "scalar",
348 Atomic::TNumeric => "numeric",
349 Atomic::TObject => "object",
350 Atomic::TNamedObject { .. } => "object",
351 Atomic::TStaticObject { .. } => "static",
352 Atomic::TSelf { .. } => "self",
353 Atomic::TParent { .. } => "parent",
354 Atomic::TCallable { .. } => "callable",
355 Atomic::TClosure { .. } => "Closure",
356 Atomic::TArray { .. } => "array",
357 Atomic::TList { .. } => "list",
358 Atomic::TNonEmptyArray { .. } => "non-empty-array",
359 Atomic::TNonEmptyList { .. } => "non-empty-list",
360 Atomic::TKeyedArray { .. } => "array",
361 Atomic::TTemplateParam { .. } => "template-param",
362 Atomic::TConditional { .. } => "conditional-type",
363 Atomic::TInterfaceString => "interface-string",
364 Atomic::TEnumString => "enum-string",
365 Atomic::TTraitString => "trait-string",
366 Atomic::TIntersection { .. } => "intersection",
367 }
368 }
369}