luaur_analysis/methods/
normalizer_normalize.rs1use crate::enums::normalization_result::NormalizationResult;
2use crate::records::fuel_initializer::FuelInitializer;
3use crate::records::normalized_extern_type::NormalizedExternType;
4use crate::records::normalized_function_type::NormalizedFunctionType;
5use crate::records::normalized_string_type::NormalizedStringType;
6use crate::records::normalized_type::NormalizedType;
7use crate::records::normalizer::Normalizer;
8use crate::records::normalizer_hit_limits::NormalizerHitLimits;
9use crate::records::type_ids::TypeIds;
10use crate::type_aliases::type_id::TypeId;
11use alloc::collections::BTreeMap;
12use alloc::sync::Arc;
13use luaur_common::records::dense_hash_set::DenseHashSet;
14
15impl Normalizer {
16 pub fn normalize(&mut self, ty: TypeId) -> Arc<NormalizedType> {
17 self.try_normalize(ty)
18 .unwrap_or_else(|| Arc::new(self.empty_normalized_type()))
19 }
20
21 pub fn try_normalize(&mut self, ty: TypeId) -> Option<Arc<NormalizedType>> {
22 match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| self.normalize_uncaught(ty)))
23 {
24 Ok(norm) => norm,
25 Err(payload) if payload.downcast_ref::<NormalizerHitLimits>().is_some() => None,
26 Err(payload) => std::panic::resume_unwind(payload),
27 }
28 }
29
30 fn normalize_uncaught(&mut self, ty: TypeId) -> Option<Arc<NormalizedType>> {
31 if self.arena.is_null() {
32 unsafe {
33 (*(*self.shared_state).ice_handler)
34 .ice_string("Normalizing types outside a module");
35 }
36 }
37
38 if let Some(shared) = self.cached_normals.get(&ty) {
39 return Some(shared.clone());
40 }
41
42 let mut norm = self.empty_normalized_type();
43 let mut seen_set_types: DenseHashSet<TypeId> = DenseHashSet::new(core::ptr::null_mut());
44 let mut seen_table_prop_pairs: crate::type_aliases::seen_table_prop_pairs::SeenTablePropPairs =
45 crate::type_aliases::seen_table_prop_pairs::SeenTablePropPairs::new((core::ptr::null(), core::ptr::null()));
46
47 let mut fi = FuelInitializer {
49 normalizer: self as *mut Normalizer,
50 initialized_fuel: false,
51 };
52 fi.fuel_initializer_not_null_normalizer(self as *mut Normalizer);
53 let _ = fi;
54
55 let res = self.union_normal_with_ty(
56 &mut norm,
57 ty,
58 &mut seen_table_prop_pairs,
59 &mut seen_set_types,
60 -1,
61 );
62
63 if res != NormalizationResult::True {
64 return None;
65 }
66
67 if norm.is_unknown() {
68 self.clear_normal(&mut norm);
69 norm.tops = unsafe { (*self.builtin_types).unknownType };
70 }
71
72 let shared = Arc::new(norm);
73
74 if shared.is_cacheable {
75 self.cached_normals.insert(ty, shared.clone());
76 }
77
78 Some(shared)
79 }
80
81 fn empty_normalized_type(&self) -> NormalizedType {
82 let never_type = unsafe { (*self.builtin_types).neverType };
83
84 NormalizedType {
85 builtin_types: self.builtin_types,
86 tops: never_type,
87 booleans: never_type,
88 extern_types: NormalizedExternType {
89 extern_types: BTreeMap::new(),
90 shape_extensions: TypeIds::type_ids(),
91 ordering: Vec::new(),
92 },
93 errors: never_type,
94 nils: never_type,
95 numbers: never_type,
96 integers: never_type,
97 strings: NormalizedStringType::never,
98 threads: never_type,
99 buffers: never_type,
100 tables: TypeIds::type_ids(),
101 functions: NormalizedFunctionType {
102 is_top: false,
103 parts: TypeIds::type_ids(),
104 },
105 tyvars: BTreeMap::new(),
106 is_cacheable: true,
107 }
108 }
109}