1use crate::enums::normalization_result::NormalizationResult;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_singleton_type::get_singleton_type;
5use crate::functions::get_type_alt_j::get_type_id;
6use crate::functions::should_early_exit::should_early_exit;
7use crate::records::any_type::AnyType;
8use crate::records::blocked_type::BlockedType;
9use crate::records::boolean_singleton::BooleanSingleton;
10use crate::records::extern_type::ExternType;
11use crate::records::free_type::FreeType;
12use crate::records::function_type::FunctionType;
13use crate::records::generic_type::GenericType;
14use crate::records::intersection_type::IntersectionType;
15use crate::records::metatable_type::MetatableType;
16use crate::records::negation_type::NegationType;
17use crate::records::never_type::NeverType;
18use crate::records::no_refine_type::NoRefineType;
19use crate::records::normalized_extern_type::NormalizedExternType;
20use crate::records::normalized_function_type::NormalizedFunctionType;
21use crate::records::normalized_string_type::NormalizedStringType;
22use crate::records::normalized_type::NormalizedType;
23use crate::records::normalizer::Normalizer;
24use crate::records::pending_expansion_type::PendingExpansionType;
25use crate::records::primitive_type::{PrimitiveType, Type as PrimType};
26use crate::records::singleton_type::SingletonType;
27use crate::records::string_singleton::StringSingleton;
28use crate::records::table_type::TableType;
29use crate::records::type_function_instance_type::TypeFunctionInstanceType;
30use crate::records::type_ids::TypeIds;
31use crate::records::union_type::UnionType;
32use crate::records::unknown_type::UnknownType;
33use crate::type_aliases::error_type::ErrorType;
34use crate::type_aliases::normalized_tyvars::NormalizedTyvars;
35use crate::type_aliases::seen_table_prop_pairs::SeenTablePropPairs;
36use crate::type_aliases::type_id::TypeId;
37use alloc::boxed::Box;
38use alloc::collections::BTreeMap;
39use core::mem;
40use luaur_common::macros::luau_assert::LUAU_ASSERT;
41use luaur_common::records::dense_hash_set::DenseHashSet;
42use luaur_common::FFlag;
43
44struct RcGuard {
46 count: *mut i32,
47}
48
49impl RcGuard {
50 fn new(count: *mut i32) -> Self {
51 unsafe {
52 *count += 1;
53 }
54 RcGuard { count }
55 }
56}
57
58impl Drop for RcGuard {
59 fn drop(&mut self) {
60 unsafe {
61 *self.count -= 1;
62 }
63 }
64}
65
66fn fresh_normalized_type(
67 builtin_types: *mut crate::records::builtin_types::BuiltinTypes,
68) -> NormalizedType {
69 let never_type = unsafe { (*builtin_types).neverType };
70 NormalizedType {
71 builtin_types,
72 tops: never_type,
73 booleans: never_type,
74 extern_types: NormalizedExternType {
75 extern_types: BTreeMap::new(),
76 shape_extensions: TypeIds::type_ids(),
77 ordering: Vec::new(),
78 },
79 errors: never_type,
80 nils: never_type,
81 numbers: never_type,
82 integers: never_type,
83 strings: NormalizedStringType::never,
84 threads: never_type,
85 buffers: never_type,
86 tables: TypeIds::type_ids(),
87 functions: NormalizedFunctionType {
88 is_top: false,
89 parts: TypeIds::type_ids(),
90 },
91 tyvars: BTreeMap::new(),
92 is_cacheable: true,
93 }
94}
95
96impl Normalizer {
97 pub fn intersect_normal_with_ty(
98 &mut self,
99 here: &mut NormalizedType,
100 there: TypeId,
101 seen_table_prop_pairs: &mut SeenTablePropPairs,
102 seen_set_types: &mut DenseHashSet<TypeId>,
103 ) -> NormalizationResult {
104 let _rc = RcGuard::new(unsafe { &mut (*self.shared_state).counters.recursion_count });
105 if !self.within_resource_limits() {
106 return NormalizationResult::HitLimits;
107 }
108
109 self.consume_fuel();
110
111 let there = unsafe { follow_type_id(there) };
112
113 if !unsafe { get_type_id::<AnyType>(there).is_null() }
114 || !unsafe { get_type_id::<UnknownType>(there).is_null() }
115 {
116 here.tops = self.intersection_of_tops(here.tops, there);
117 return NormalizationResult::True;
118 } else if unsafe { get_type_id::<NeverType>(here.tops).is_null() } {
119 self.clear_normal(here);
120 return self.union_normal_with_ty(
121 here,
122 there,
123 seen_table_prop_pairs,
124 seen_set_types,
125 -1,
126 );
127 } else if !unsafe { get_type_id::<UnionType>(there).is_null() } {
128 let mut norm = fresh_normalized_type(self.builtin_types);
129 let options = unsafe { (*get_type_id::<UnionType>(there)).options.clone() };
130 for opt in options {
131 let res = self.union_normal_with_ty(
132 &mut norm,
133 opt,
134 seen_table_prop_pairs,
135 seen_set_types,
136 -1,
137 );
138 if res != NormalizationResult::True {
139 return res;
140 }
141 }
142 return self.intersect_normals(here, &norm, -1);
143 } else if !unsafe { get_type_id::<IntersectionType>(there).is_null() } {
144 let parts = unsafe { (*get_type_id::<IntersectionType>(there)).parts.clone() };
145 for part in parts {
146 let res = self.intersect_normal_with_ty(
147 here,
148 part,
149 seen_table_prop_pairs,
150 seen_set_types,
151 );
152 if res != NormalizationResult::True {
153 return res;
154 }
155 }
156 return NormalizationResult::True;
157 } else if !unsafe { get_type_id::<GenericType>(there).is_null() }
158 || !unsafe { get_type_id::<FreeType>(there).is_null() }
159 || !unsafe { get_type_id::<BlockedType>(there).is_null() }
160 || !unsafe { get_type_id::<PendingExpansionType>(there).is_null() }
161 || !unsafe { get_type_id::<TypeFunctionInstanceType>(there).is_null() }
162 {
163 let mut there_norm = fresh_normalized_type(self.builtin_types);
164 let mut top_norm = fresh_normalized_type(self.builtin_types);
165 top_norm.tops = unsafe { (*self.builtin_types).unknownType };
166 there_norm.tyvars.insert(there, Box::new(top_norm));
167 here.is_cacheable = false;
168 return self.intersect_normals(here, &there_norm, -1);
169 }
170
171 let mut tyvars: NormalizedTyvars = mem::take(&mut here.tyvars);
172
173 if !unsafe { get_type_id::<FunctionType>(there).is_null() } {
174 let mut functions = mem::replace(
175 &mut here.functions,
176 NormalizedFunctionType {
177 is_top: false,
178 parts: TypeIds::type_ids(),
179 },
180 );
181 self.clear_normal(here);
182 self.intersect_functions_with_function(&mut functions, there);
183 here.functions = functions;
184 } else if !unsafe { get_type_id::<TableType>(there).is_null() }
185 || !unsafe { get_type_id::<MetatableType>(there).is_null() }
186 {
187 if self.use_new_luau_solver() {
188 let mut extern_types = mem::replace(
189 &mut here.extern_types,
190 NormalizedExternType {
191 extern_types: BTreeMap::new(),
192 shape_extensions: TypeIds::type_ids(),
193 ordering: Vec::new(),
194 },
195 );
196 let mut tables = mem::replace(&mut here.tables, TypeIds::type_ids());
197 self.clear_normal(here);
198
199 if FFlag::LuauExternTypesNormalizeWithShapes.get() {
200 if extern_types.is_never() {
201 self.intersect_tables_with_table(
202 &mut tables,
203 there,
204 seen_table_prop_pairs,
205 seen_set_types,
206 );
207 } else {
208 self.intersect_extern_types_with_shape(&mut extern_types, there);
209 }
210 } else {
211 self.intersect_tables_with_table(
212 &mut tables,
213 there,
214 seen_table_prop_pairs,
215 seen_set_types,
216 );
217 }
218
219 here.tables = tables;
220 here.extern_types = extern_types;
221 } else {
222 let mut tables = mem::replace(&mut here.tables, TypeIds::type_ids());
223 self.clear_normal(here);
224 self.intersect_tables_with_table(
225 &mut tables,
226 there,
227 seen_table_prop_pairs,
228 seen_set_types,
229 );
230 here.tables = tables;
231 }
232 } else if !unsafe { get_type_id::<ExternType>(there).is_null() } {
233 let mut nct = mem::replace(
234 &mut here.extern_types,
235 NormalizedExternType {
236 extern_types: BTreeMap::new(),
237 shape_extensions: TypeIds::type_ids(),
238 ordering: Vec::new(),
239 },
240 );
241 self.clear_normal(here);
242 self.intersect_extern_types_with_extern_type(&mut nct, there);
243 here.extern_types = nct;
244 } else if !unsafe { get_type_id::<ErrorType>(there).is_null() } {
245 let errors = here.errors;
246 self.clear_normal(here);
247 here.errors = if !unsafe { get_type_id::<ErrorType>(errors).is_null() } {
248 errors
249 } else {
250 there
251 };
252 } else if !unsafe { get_type_id::<PrimitiveType>(there).is_null() } {
253 let booleans = here.booleans;
254 let nils = here.nils;
255 let numbers = here.numbers;
256 let integers = here.integers;
257 let strings = mem::replace(&mut here.strings, NormalizedStringType::never);
258 let functions = mem::replace(
259 &mut here.functions,
260 NormalizedFunctionType {
261 is_top: false,
262 parts: TypeIds::type_ids(),
263 },
264 );
265 let threads = here.threads;
266 let buffers = here.buffers;
267 let tables = mem::replace(&mut here.tables, TypeIds::type_ids());
268
269 self.clear_normal(here);
270
271 let ptv = unsafe { &*get_type_id::<PrimitiveType>(there) };
272 match ptv.r#type {
273 PrimType::Boolean => here.booleans = booleans,
274 PrimType::NilType => here.nils = nils,
275 PrimType::Number => here.numbers = numbers,
276 PrimType::Integer if FFlag::LuauIntegerType2.get() => here.integers = integers,
277 PrimType::String => here.strings = strings,
278 PrimType::Thread => here.threads = threads,
279 PrimType::Buffer => here.buffers = buffers,
280 PrimType::Function => here.functions = functions,
281 PrimType::Table => here.tables = tables,
282 _ => LUAU_ASSERT!(false),
283 }
284 } else if !unsafe { get_type_id::<SingletonType>(there).is_null() } {
285 let booleans = here.booleans;
286 let strings = mem::replace(&mut here.strings, NormalizedStringType::never);
287
288 self.clear_normal(here);
289
290 let stv = unsafe { get_type_id::<SingletonType>(there) };
291 if !get_singleton_type::<BooleanSingleton>(stv).is_null() {
292 here.booleans = self.intersection_of_bools(booleans, there);
293 } else if !get_singleton_type::<StringSingleton>(stv).is_null() {
294 let sstv = unsafe { &*get_singleton_type::<StringSingleton>(stv) };
295 if strings.includes(&sstv.value) {
296 here.strings.singletons.insert(sstv.value.clone(), there);
297 }
298 } else {
299 LUAU_ASSERT!(false);
300 }
301 } else if !unsafe { get_type_id::<NegationType>(there).is_null() } {
302 let ntv_ty = unsafe { (*get_type_id::<NegationType>(there)).ty };
303 let t = unsafe { follow_type_id(ntv_ty) };
304 if !unsafe { get_type_id::<PrimitiveType>(t).is_null() } {
305 self.subtract_primitive(here, ntv_ty);
306 } else if !unsafe { get_type_id::<SingletonType>(t).is_null() } {
307 self.subtract_singleton(here, unsafe { follow_type_id(ntv_ty) });
308 } else if !unsafe { get_type_id::<ExternType>(t).is_null() } {
309 let res = self.intersect_normal_with_negation_ty(t, here);
310 if should_early_exit(res) {
311 here.tyvars = tyvars;
312 return res;
313 }
314 } else if !unsafe { get_type_id::<UnionType>(t).is_null() } {
315 let options = unsafe { (*get_type_id::<UnionType>(t)).options.clone() };
316 for part in options {
317 let res = self.intersect_normal_with_negation_ty(part, here);
318 if should_early_exit(res) {
319 here.tyvars = tyvars;
320 return res;
321 }
322 }
323 } else if !unsafe { get_type_id::<AnyType>(t).is_null() } {
324 here.tyvars = tyvars;
327 return NormalizationResult::True;
328 } else if !unsafe { get_type_id::<NoRefineType>(t).is_null() } {
329 here.tyvars = tyvars;
331 return NormalizationResult::True;
332 } else if !unsafe { get_type_id::<NeverType>(t).is_null() } {
333 here.tyvars = tyvars;
335 return NormalizationResult::True;
336 } else if !unsafe { get_type_id::<UnknownType>(t).is_null() } {
337 self.clear_normal(here);
339 here.tyvars = tyvars;
340 return NormalizationResult::True;
341 } else if !unsafe { get_type_id::<ErrorType>(t).is_null() } {
342 let errors = here.errors;
344 self.clear_normal(here);
345 here.errors = if !unsafe { get_type_id::<ErrorType>(errors).is_null() } {
346 errors
347 } else {
348 t
349 };
350 } else if !unsafe { get_type_id::<NegationType>(t).is_null() } {
351 let nt_ty = unsafe { (*get_type_id::<NegationType>(t)).ty };
352 here.tyvars = tyvars;
353 return self.intersect_normal_with_ty(
354 here,
355 nt_ty,
356 seen_table_prop_pairs,
357 seen_set_types,
358 );
359 } else {
360 LUAU_ASSERT!(false);
363 }
364 } else if !unsafe { get_type_id::<NeverType>(there).is_null() } {
365 here.extern_types.reset_to_never();
366 } else if !unsafe { get_type_id::<NoRefineType>(there).is_null() } {
367 here.tyvars = tyvars;
369 return NormalizationResult::True;
370 } else {
371 LUAU_ASSERT!(false);
372 }
373
374 let res = self.intersect_tyvars_with_ty(
375 &mut tyvars,
376 there,
377 seen_table_prop_pairs,
378 seen_set_types,
379 );
380 if res != NormalizationResult::True {
381 here.tyvars = tyvars;
382 return res;
383 }
384 here.tyvars = tyvars;
385
386 NormalizationResult::True
387 }
388}