luaur_analysis/methods/
normalizer_intersect_normals.rs1use crate::enums::normalization_result::NormalizationResult;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::functions::is_shallow_inhabited::is_shallow_inhabited;
5use crate::functions::tyvar_index::tyvar_index;
6use crate::records::never_type::NeverType;
7use crate::records::normalized_type::NormalizedType;
8use crate::records::normalizer::Normalizer;
9use crate::type_aliases::type_id::TypeId;
10use alloc::boxed::Box;
11use luaur_common::macros::luau_assert::LUAU_ASSERT;
12use luaur_common::FFlag;
13
14struct RcGuard {
16 count: *mut i32,
17}
18
19impl RcGuard {
20 fn new(count: *mut i32) -> Self {
21 unsafe {
22 *count += 1;
23 }
24 RcGuard { count }
25 }
26}
27
28impl Drop for RcGuard {
29 fn drop(&mut self) {
30 unsafe {
31 *self.count -= 1;
32 }
33 }
34}
35
36impl Normalizer {
37 pub fn intersect_normals(
39 &mut self,
40 here: &mut NormalizedType,
41 there: &NormalizedType,
42 ignore_smaller_tyvars: i32,
43 ) -> NormalizationResult {
44 let _rc = RcGuard::new(unsafe { &mut (*self.shared_state).counters.recursion_count });
45 if !self.within_resource_limits() {
46 return NormalizationResult::HitLimits;
47 }
48
49 self.consume_fuel();
50
51 if unsafe { get_type_id::<NeverType>(there.tops).is_null() } {
52 here.tops = self.intersection_of_tops(here.tops, there.tops);
53 return NormalizationResult::True;
54 } else if unsafe { get_type_id::<NeverType>(here.tops).is_null() } {
55 self.clear_normal(here);
56 return self.union_normals(here, there, ignore_smaller_tyvars);
57 }
58
59 for (tyvar, _inter) in there.tyvars.iter() {
60 let index = tyvar_index(*tyvar);
61 if ignore_smaller_tyvars < index {
62 let fresh = !here.tyvars.contains_key(tyvar);
63 if fresh {
64 let mut entry = Box::new(fresh_normalized_type(self.builtin_types));
65 let res = self.union_normals(&mut entry, here, index);
66 if res != NormalizationResult::True {
67 return res;
68 }
69 here.tyvars.insert(*tyvar, entry);
70 }
71 }
72 }
73
74 here.booleans = self.intersection_of_bools(here.booleans, there.booleans);
75
76 self.intersect_extern_types(&mut here.extern_types, &there.extern_types);
77 here.errors = if !unsafe { get_type_id::<NeverType>(there.errors).is_null() } {
78 there.errors
79 } else {
80 here.errors
81 };
82 here.nils = if !unsafe { get_type_id::<NeverType>(there.nils).is_null() } {
83 there.nils
84 } else {
85 here.nils
86 };
87 here.numbers = if !unsafe { get_type_id::<NeverType>(there.numbers).is_null() } {
88 there.numbers
89 } else {
90 here.numbers
91 };
92 if FFlag::LuauIntegerType2.get() {
93 here.integers = if !unsafe { get_type_id::<NeverType>(there.integers).is_null() } {
94 there.integers
95 } else {
96 here.integers
97 };
98 }
99 self.intersect_strings(&mut here.strings, &there.strings);
100 here.threads = if !unsafe { get_type_id::<NeverType>(there.threads).is_null() } {
101 there.threads
102 } else {
103 here.threads
104 };
105 here.buffers = if !unsafe { get_type_id::<NeverType>(there.buffers).is_null() } {
106 there.buffers
107 } else {
108 here.buffers
109 };
110 self.intersect_functions(&mut here.functions, &there.functions);
111 self.intersect_tables(&mut here.tables, &there.tables);
112
113 let tyvar_keys: Vec<TypeId> = here.tyvars.keys().copied().collect();
114 for tyvar in tyvar_keys {
115 let mut inter = match here.tyvars.remove(&tyvar) {
116 Some(b) => b,
117 None => continue,
118 };
119 let index = tyvar_index(tyvar);
120 LUAU_ASSERT!(ignore_smaller_tyvars < index);
121 let res = match there.tyvars.get(&tyvar) {
122 None => self.intersect_normals(&mut inter, there, index),
123 Some(found) => self.intersect_normals(&mut inter, found, index),
124 };
125 if res != NormalizationResult::True {
126 here.tyvars.insert(tyvar, inter);
127 return res;
128 }
129 if is_shallow_inhabited(&inter) {
130 here.tyvars.insert(tyvar, inter);
131 }
132 }
134 NormalizationResult::True
135 }
136}
137
138fn fresh_normalized_type(
139 builtin_types: *mut crate::records::builtin_types::BuiltinTypes,
140) -> NormalizedType {
141 let never_type = unsafe { (*builtin_types).neverType };
142 NormalizedType {
143 builtin_types,
144 tops: never_type,
145 booleans: never_type,
146 extern_types: crate::records::normalized_extern_type::NormalizedExternType {
147 extern_types: alloc::collections::BTreeMap::new(),
148 shape_extensions: crate::records::type_ids::TypeIds::type_ids(),
149 ordering: Vec::new(),
150 },
151 errors: never_type,
152 nils: never_type,
153 numbers: never_type,
154 integers: never_type,
155 strings: crate::records::normalized_string_type::NormalizedStringType::never,
156 threads: never_type,
157 buffers: never_type,
158 tables: crate::records::type_ids::TypeIds::type_ids(),
159 functions: crate::records::normalized_function_type::NormalizedFunctionType {
160 is_top: false,
161 parts: crate::records::type_ids::TypeIds::type_ids(),
162 },
163 tyvars: alloc::collections::BTreeMap::new(),
164 is_cacheable: true,
165 }
166}