mago_codex/ttype/
combination.rs

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