Skip to main content

luaur_analysis/methods/
normalizer_is_inhabited_normalize_alt_d.rs

1use crate::enums::normalization_result::NormalizationResult;
2use crate::functions::follow_type::follow_type_id;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::records::intersection_type::IntersectionType;
5use crate::records::metatable_type::MetatableType;
6use crate::records::never_type::NeverType;
7use crate::records::normalizer::Normalizer;
8use crate::records::table_type::TableType;
9use crate::records::union_type::UnionType;
10use crate::type_aliases::type_id::TypeId;
11use luaur_common::records::dense_hash_set::DenseHashSet;
12
13struct RecursionCountGuard {
14    count: *mut i32,
15}
16
17impl RecursionCountGuard {
18    fn new(count: *mut i32) -> Self {
19        unsafe {
20            *count += 1;
21        }
22        Self { count }
23    }
24}
25
26impl Drop for RecursionCountGuard {
27    fn drop(&mut self) {
28        unsafe {
29            debug_assert!(*self.count > 0);
30            *self.count -= 1;
31        }
32    }
33}
34
35impl Normalizer {
36    pub fn is_inhabited_type_id_set_type_id(
37        &mut self,
38        ty: TypeId,
39        seen: &mut DenseHashSet<TypeId>,
40    ) -> NormalizationResult {
41        let _rc =
42            RecursionCountGuard::new(unsafe { &mut (*self.shared_state).counters.recursion_count });
43
44        if !self.within_resource_limits() {
45            return NormalizationResult::HitLimits;
46        }
47
48        self.consume_fuel();
49
50        let ty = unsafe { follow_type_id(ty) };
51
52        if !unsafe { get_type_id::<NeverType>(ty).is_null() } {
53            return NormalizationResult::False;
54        }
55
56        if unsafe { get_type_id::<IntersectionType>(ty).is_null() }
57            && unsafe { get_type_id::<UnionType>(ty).is_null() }
58            && unsafe { get_type_id::<TableType>(ty).is_null() }
59            && unsafe { get_type_id::<MetatableType>(ty).is_null() }
60        {
61            return NormalizationResult::True;
62        }
63
64        if seen.contains(&ty) {
65            return NormalizationResult::True;
66        }
67
68        seen.insert(ty);
69
70        if let Some(ttv) = unsafe { get_type_id::<TableType>(ty).as_ref() } {
71            for (_k, prop) in &ttv.props {
72                if self.use_new_luau_solver() {
73                    if let Some(ty) = prop.read_ty {
74                        let res = self.is_inhabited_type_id_set_type_id(ty, seen);
75                        if res != NormalizationResult::True {
76                            return res;
77                        }
78                    }
79                } else {
80                    let res = self.is_inhabited_type_id_set_type_id(prop.read_ty.unwrap(), seen);
81                    if res != NormalizationResult::True {
82                        return res;
83                    }
84                }
85            }
86            return NormalizationResult::True;
87        }
88
89        if let Some(mtv) = unsafe { get_type_id::<MetatableType>(ty).as_ref() } {
90            let res = self.is_inhabited_type_id_set_type_id(mtv.table, seen);
91            if res != NormalizationResult::True {
92                return res;
93            }
94            return self.is_inhabited_type_id_set_type_id(mtv.metatable, seen);
95        }
96
97        let norm = self.normalize(ty);
98        self.is_inhabited_normalized_type_set_type_id(norm.as_ref(), seen)
99    }
100}