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<crate::compact::SimpleType>,
18 pub default: Option<crate::compact::SimpleType>,
20 pub is_variadic: bool,
21 pub is_byref: bool,
22 pub is_optional: bool,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
30pub enum Variance {
31 #[default]
33 Invariant,
34 Covariant,
36 Contravariant,
38}
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
45pub struct TemplateParam {
46 pub name: Arc<str>,
47 pub bound: Option<Union>,
48 pub variance: Variance,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
56pub enum ArrayKey {
57 String(Arc<str>),
58 Int(i64),
59}
60
61#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
62pub struct KeyedProperty {
63 pub ty: Union,
64 pub optional: bool,
65}
66
67#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub enum Atomic {
73 TString,
76 TLiteralString(Arc<str>),
78 TClassString(Option<Arc<str>>),
80 TNonEmptyString,
82 TNumericString,
84
85 TInt,
87 TLiteralInt(i64),
89 TIntRange { min: Option<i64>, max: Option<i64> },
91 TPositiveInt,
93 TNegativeInt,
95 TNonNegativeInt,
97
98 TFloat,
100 TLiteralFloat(i64, i64), TBool,
105 TTrue,
107 TFalse,
109
110 TNull,
112
113 TVoid,
116 TNever,
118 TMixed,
120 TScalar,
122 TNumeric,
124
125 TObject,
128 TNamedObject {
130 fqcn: Arc<str>,
131 type_params: Vec<Union>,
133 },
134 TStaticObject { fqcn: Arc<str> },
136 TSelf { fqcn: Arc<str> },
138 TParent { fqcn: Arc<str> },
140
141 TCallable {
144 params: Option<Vec<FnParam>>,
145 return_type: Option<Box<Union>>,
146 },
147 TClosure {
149 params: Vec<FnParam>,
150 return_type: Box<Union>,
151 this_type: Option<Box<Union>>,
152 },
153
154 TArray { key: Box<Union>, value: Box<Union> },
157 TList { value: Box<Union> },
159 TNonEmptyArray { key: Box<Union>, value: Box<Union> },
161 TNonEmptyList { value: Box<Union> },
163 TKeyedArray {
165 properties: IndexMap<ArrayKey, KeyedProperty>,
166 is_open: bool,
168 is_list: bool,
170 },
171
172 TTemplateParam {
175 name: Arc<str>,
176 as_type: Box<Union>,
177 defining_entity: Arc<str>,
179 },
180 TConditional {
182 subject: Box<Union>,
183 if_true: Box<Union>,
184 if_false: Box<Union>,
185 },
186
187 TInterfaceString,
190 TEnumString,
192 TTraitString,
194
195 TLiteralEnumCase {
198 enum_fqcn: Arc<str>,
199 case_name: Arc<str>,
200 },
201
202 TIntersection { parts: Vec<Union> },
205}
206
207impl Atomic {
208 pub fn can_be_falsy(&self) -> bool {
210 match self {
211 Atomic::TNull
212 | Atomic::TFalse
213 | Atomic::TBool
214 | Atomic::TNever
215 | Atomic::TLiteralInt(0)
216 | Atomic::TLiteralFloat(0, 0)
217 | Atomic::TInt
218 | Atomic::TFloat
219 | Atomic::TNumeric
220 | Atomic::TScalar
221 | Atomic::TMixed
222 | Atomic::TString
223 | Atomic::TNonEmptyString
224 | Atomic::TArray { .. }
225 | Atomic::TList { .. }
226 | Atomic::TNonEmptyArray { .. }
227 | Atomic::TNonEmptyList { .. } => true,
228
229 Atomic::TLiteralString(s) => s.as_ref().is_empty() || s.as_ref() == "0",
230
231 Atomic::TKeyedArray { properties, .. } => properties.is_empty(),
232
233 _ => false,
234 }
235 }
236
237 pub fn can_be_truthy(&self) -> bool {
239 match self {
240 Atomic::TNever
241 | Atomic::TVoid
242 | Atomic::TNull
243 | Atomic::TFalse
244 | Atomic::TLiteralInt(0)
245 | Atomic::TLiteralFloat(0, 0) => false,
246 Atomic::TLiteralString(s) if s.as_ref() == "" || s.as_ref() == "0" => false,
247 _ => true,
248 }
249 }
250
251 pub fn is_numeric(&self) -> bool {
253 matches!(
254 self,
255 Atomic::TInt
256 | Atomic::TLiteralInt(_)
257 | Atomic::TIntRange { .. }
258 | Atomic::TPositiveInt
259 | Atomic::TNegativeInt
260 | Atomic::TNonNegativeInt
261 | Atomic::TFloat
262 | Atomic::TLiteralFloat(..)
263 | Atomic::TNumeric
264 | Atomic::TNumericString
265 )
266 }
267
268 pub fn is_int(&self) -> bool {
270 matches!(
271 self,
272 Atomic::TInt
273 | Atomic::TLiteralInt(_)
274 | Atomic::TIntRange { .. }
275 | Atomic::TPositiveInt
276 | Atomic::TNegativeInt
277 | Atomic::TNonNegativeInt
278 )
279 }
280
281 pub fn is_string(&self) -> bool {
283 matches!(
284 self,
285 Atomic::TString
286 | Atomic::TLiteralString(_)
287 | Atomic::TClassString(_)
288 | Atomic::TNonEmptyString
289 | Atomic::TNumericString
290 | Atomic::TInterfaceString
291 | Atomic::TEnumString
292 | Atomic::TTraitString
293 )
294 }
295
296 pub fn is_array(&self) -> bool {
298 matches!(
299 self,
300 Atomic::TArray { .. }
301 | Atomic::TList { .. }
302 | Atomic::TNonEmptyArray { .. }
303 | Atomic::TNonEmptyList { .. }
304 | Atomic::TKeyedArray { .. }
305 )
306 }
307
308 pub fn is_object(&self) -> bool {
310 matches!(
311 self,
312 Atomic::TObject
313 | Atomic::TNamedObject { .. }
314 | Atomic::TStaticObject { .. }
315 | Atomic::TSelf { .. }
316 | Atomic::TParent { .. }
317 | Atomic::TIntersection { .. }
318 )
319 }
320
321 pub fn is_callable(&self) -> bool {
323 matches!(self, Atomic::TCallable { .. } | Atomic::TClosure { .. })
324 }
325
326 pub fn named_object_fqcn(&self) -> Option<&str> {
328 match self {
329 Atomic::TNamedObject { fqcn, .. }
330 | Atomic::TStaticObject { fqcn }
331 | Atomic::TSelf { fqcn }
332 | Atomic::TParent { fqcn } => Some(fqcn.as_ref()),
333 _ => None,
334 }
335 }
336
337 pub fn type_name(&self) -> &'static str {
339 match self {
340 Atomic::TString
341 | Atomic::TLiteralString(_)
342 | Atomic::TNonEmptyString
343 | Atomic::TNumericString => "string",
344 Atomic::TClassString(_) => "class-string",
345 Atomic::TInt | Atomic::TLiteralInt(_) | Atomic::TIntRange { .. } => "int",
346 Atomic::TPositiveInt => "positive-int",
347 Atomic::TNegativeInt => "negative-int",
348 Atomic::TNonNegativeInt => "non-negative-int",
349 Atomic::TFloat | Atomic::TLiteralFloat(..) => "float",
350 Atomic::TBool => "bool",
351 Atomic::TTrue => "true",
352 Atomic::TFalse => "false",
353 Atomic::TNull => "null",
354 Atomic::TVoid => "void",
355 Atomic::TNever => "never",
356 Atomic::TMixed => "mixed",
357 Atomic::TScalar => "scalar",
358 Atomic::TNumeric => "numeric",
359 Atomic::TObject => "object",
360 Atomic::TNamedObject { .. } => "object",
361 Atomic::TStaticObject { .. } => "static",
362 Atomic::TSelf { .. } => "self",
363 Atomic::TParent { .. } => "parent",
364 Atomic::TCallable { .. } => "callable",
365 Atomic::TClosure { .. } => "Closure",
366 Atomic::TArray { .. } => "array",
367 Atomic::TList { .. } => "list",
368 Atomic::TNonEmptyArray { .. } => "non-empty-array",
369 Atomic::TNonEmptyList { .. } => "non-empty-list",
370 Atomic::TKeyedArray { .. } => "array",
371 Atomic::TTemplateParam { .. } => "template-param",
372 Atomic::TConditional { .. } => "conditional-type",
373 Atomic::TInterfaceString => "interface-string",
374 Atomic::TEnumString => "enum-string",
375 Atomic::TTraitString => "trait-string",
376 Atomic::TLiteralEnumCase { .. } => "enum-case",
377 Atomic::TIntersection { .. } => "intersection",
378 }
379 }
380}