luaur_analysis/methods/
unifier_deeply_optional.rs1use crate::functions::follow_type::follow_type_id;
2use crate::functions::get_mutable_type::get_mutable_type_id;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::functions::is_optional::is_optional;
5use crate::records::table_type::TableType;
6use crate::records::unifier::Unifier;
7use crate::records::union_type::UnionType;
8use crate::type_aliases::type_id::TypeId;
9use luaur_common::macros::luau_assert::LUAU_ASSERT;
10use std::collections::HashMap;
11
12impl Unifier {
13 pub fn unifier_deeply_optional(
14 &mut self,
15 mut ty: TypeId,
16 seen: &mut HashMap<TypeId, TypeId>,
17 ) -> TypeId {
18 ty = unsafe { follow_type_id(ty) };
19
20 if is_optional(ty) {
21 return ty;
22 }
23
24 let ttv_ptr = unsafe { get_type_id::<TableType>(ty) };
26
27 if !ttv_ptr.is_null() {
28 let ttv = unsafe { &*ttv_ptr };
29
30 if let Some(&result) = seen.get(&ty) {
31 return result;
32 }
33
34 let result = unsafe { (*self.types).add_type(ttv.clone()) };
36
37 seen.insert(ty, result);
39
40 let result_ttv_ptr = unsafe { get_mutable_type_id::<TableType>(result) };
42 LUAU_ASSERT!(!result_ttv_ptr.is_null());
43 let result_ttv = unsafe { &mut *result_ttv_ptr };
44
45 for (_name, prop) in &mut result_ttv.props {
47 let prop_ty = prop.read_ty.or(prop.write_ty).unwrap_or(core::ptr::null());
48 let new_prop_ty = self.unifier_deeply_optional(prop_ty, seen);
49 prop.read_ty = Some(new_prop_ty);
50 prop.write_ty = Some(new_prop_ty);
51 }
52
53 let builtin_types = unsafe { &*self.builtin_types };
55 let union_types = alloc::vec![builtin_types.nilType, result];
56 let union_type = UnionType {
57 options: union_types,
58 };
59 unsafe { (*self.types).add_type(union_type) }
60 } else {
61 let builtin_types = unsafe { &*self.builtin_types };
63 let union_types = alloc::vec![builtin_types.nilType, ty];
64 let union_type = UnionType {
65 options: union_types,
66 };
67 unsafe { (*self.types).add_type(union_type) }
68 }
69 }
70}