mago_codex/ttype/
combination.rs

1use std::collections::BTreeMap;
2
3use ahash::HashMap;
4use ahash::HashSet;
5use ordered_float::OrderedFloat;
6
7use mago_interner::StringIdentifier;
8
9use crate::ttype::atomic::TAtomic;
10use crate::ttype::atomic::array::key::ArrayKey;
11use crate::ttype::atomic::derived::TDerived;
12use crate::ttype::atomic::scalar::int::TInteger;
13use crate::ttype::union::TUnion;
14
15#[derive(Debug)]
16pub struct TypeCombination {
17    pub value_types: HashMap<String, TAtomic>,
18    pub has_object_top_type: bool,
19    pub enum_names: HashSet<(StringIdentifier, Option<StringIdentifier>)>,
20    pub object_type_params: HashMap<String, (StringIdentifier, Vec<TUnion>)>,
21    pub object_static: HashMap<StringIdentifier, bool>,
22    pub list_array_counts: Option<HashSet<usize>>,
23    pub list_array_sometimes_filled: bool,
24    pub list_array_always_filled: bool,
25    pub keyed_array_sometimes_filled: bool,
26    pub keyed_array_always_filled: bool,
27    pub has_empty_array: bool,
28    pub has_keyed_array: bool,
29    pub keyed_array_entries: BTreeMap<ArrayKey, (bool, TUnion)>,
30    pub list_array_entries: BTreeMap<usize, (bool, TUnion)>,
31    pub keyed_array_parameters: Option<(TUnion, TUnion)>,
32    pub list_array_parameter: Option<TUnion>,
33    pub falsy_mixed: Option<bool>,
34    pub truthy_mixed: Option<bool>,
35    pub nonnull_mixed: Option<bool>,
36    pub generic_mixed: bool,
37    pub has_mixed: bool,
38    pub mixed_from_loop_isset: Option<bool>,
39    pub integers: HashSet<TInteger>,
40    pub literal_strings: HashSet<String>,
41    pub literal_floats: HashSet<OrderedFloat<f64>>,
42    pub class_string_types: HashMap<String, TAtomic>,
43    pub derived_types: HashSet<TDerived>,
44    pub resource: bool,
45    pub open_resource: bool,
46    pub closed_resource: bool,
47}
48
49impl Default for TypeCombination {
50    fn default() -> Self {
51        Self::new()
52    }
53}
54
55impl TypeCombination {
56    pub fn new() -> Self {
57        Self {
58            value_types: HashMap::default(),
59            has_object_top_type: false,
60            object_type_params: HashMap::default(),
61            object_static: HashMap::default(),
62            list_array_counts: Some(HashSet::default()),
63            list_array_sometimes_filled: false,
64            list_array_always_filled: true,
65            keyed_array_sometimes_filled: false,
66            keyed_array_always_filled: true,
67            has_empty_array: false,
68            has_keyed_array: false,
69            keyed_array_entries: BTreeMap::new(),
70            list_array_entries: BTreeMap::new(),
71            keyed_array_parameters: None,
72            list_array_parameter: None,
73            falsy_mixed: None,
74            truthy_mixed: None,
75            nonnull_mixed: None,
76            generic_mixed: false,
77            has_mixed: false,
78            mixed_from_loop_isset: None,
79            literal_strings: HashSet::default(),
80            integers: HashSet::default(),
81            literal_floats: HashSet::default(),
82            class_string_types: HashMap::default(),
83            enum_names: HashSet::default(),
84            derived_types: HashSet::default(),
85            resource: false,
86            open_resource: false,
87            closed_resource: false,
88        }
89    }
90
91    #[inline]
92    pub fn is_simple(&self) -> bool {
93        if self.value_types.len() == 1
94            && !self.has_keyed_array
95            && !self.has_empty_array
96            && !self.resource
97            && !self.open_resource
98            && !self.closed_resource
99            && let (None, None) = (&self.keyed_array_parameters, &self.list_array_parameter)
100        {
101            return self.keyed_array_entries.is_empty()
102                && self.list_array_entries.is_empty()
103                && self.object_type_params.is_empty()
104                && self.enum_names.is_empty()
105                && self.literal_strings.is_empty()
106                && self.class_string_types.is_empty()
107                && self.integers.is_empty()
108                && self.derived_types.is_empty();
109        }
110
111        false
112    }
113}