Skip to main content

luaur_analysis/methods/
clone_public_interface_clean_module.rs

1use crate::enums::table_state::TableState;
2use crate::functions::get_mutable_type::get_mutable_type_id;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::records::blocked_type::BlockedType;
5use crate::records::clone_public_interface::ClonePublicInterface;
6use crate::records::free_type::FreeType;
7use crate::records::function_type::FunctionType;
8use crate::records::generic_type::GenericType;
9use crate::records::generic_type_finder::GenericTypeFinder;
10use crate::records::generic_type_visitor::{GenericTypeVisitor, GenericTypeVisitorTrait};
11use crate::records::pending_expansion_type::PendingExpansionType;
12use crate::records::table_type::TableType;
13use crate::records::type_level::TypeLevel;
14use crate::type_aliases::type_id::TypeId;
15use core::ffi::c_void;
16use luaur_common::records::dense_hash_set::DenseHashSet;
17
18/// `GenericTypeFinder::visit` overrides are declared as inherent methods on the
19/// record (Instantiation.h:84-114). The visitor driver `traverse` needs the
20/// `GenericTypeVisitorTrait` surface, so wire the trait to those inherent
21/// methods here (the dispatch points `ClonePublicInterface::clean` relies on).
22impl GenericTypeVisitorTrait for GenericTypeFinder {
23    type Seen = DenseHashSet<*mut c_void>;
24
25    fn visitor_base(&mut self) -> &mut GenericTypeVisitor<Self::Seen> {
26        &mut self.base.base
27    }
28
29    fn visit_type_id(&mut self, ty: TypeId) -> bool {
30        GenericTypeFinder::visit_type_id(self, ty)
31    }
32
33    fn visit_type_pack_id(&mut self, tp: crate::type_aliases::type_pack_id::TypePackId) -> bool {
34        GenericTypeFinder::visit_type_pack_id(self, tp)
35    }
36
37    fn visit_type_id_function_type(&mut self, ty: TypeId, ftv: &FunctionType) -> bool {
38        GenericTypeFinder::visit_type_id_function_type(self, ty, ftv)
39    }
40
41    fn visit_type_id_table_type(&mut self, ty: TypeId, ttv: &TableType) -> bool {
42        GenericTypeFinder::visit_type_id_table_type(self, ty, ttv)
43    }
44
45    fn visit_type_id_generic_type(&mut self, ty: TypeId, gtv: &GenericType) -> bool {
46        GenericTypeFinder::visit_type_id_generic_type(self, ty, gtv)
47    }
48
49    fn visit_type_pack_id_generic_type_pack(
50        &mut self,
51        tp: crate::type_aliases::type_pack_id::TypePackId,
52        gtp: &crate::records::generic_type_pack::GenericTypePack,
53    ) -> bool {
54        GenericTypeFinder::visit_type_pack_id_generic_type_pack(self, tp, gtp)
55    }
56
57    fn visit_type_id_extern_type(
58        &mut self,
59        ty: TypeId,
60        etv: &crate::records::extern_type::ExternType,
61    ) -> bool {
62        GenericTypeFinder::visit_type_id_extern_type(self, ty, etv)
63    }
64}
65
66impl ClonePublicInterface {
67    /// `TypeId ClonePublicInterface::clean(TypeId ty)`.
68    /// Reference: `Module.cpp:167-208`.
69    pub fn clean_type_id(&mut self, ty: TypeId) -> TypeId {
70        let mut result = self.base.clone_type_id(ty);
71
72        let ftv = unsafe { get_mutable_type_id::<FunctionType>(result) };
73        if !ftv.is_null() {
74            let ftv = unsafe { &mut *ftv };
75            if ftv.generics.is_empty() && ftv.generic_packs.is_empty() {
76                let mut marker = GenericTypeFinder::generic_type_finder();
77                marker.traverse_type_id(result);
78
79                if !marker.found {
80                    ftv.has_no_free_or_generic_types = true;
81                }
82            }
83
84            ftv.level = TypeLevel::new(0, 0);
85        } else {
86            let ttv = unsafe { get_mutable_type_id::<TableType>(result) };
87            if !ttv.is_null() {
88                let ttv = unsafe { &mut *ttv };
89                ttv.level = TypeLevel::new(0, 0);
90                if self.is_new_solver() {
91                    ttv.scope = core::ptr::null_mut();
92                    ttv.state = TableState::Sealed;
93                }
94            }
95        }
96
97        if self.is_new_solver() {
98            if unsafe {
99                !get_type_id::<FreeType>(ty).is_null()
100                    || !get_type_id::<BlockedType>(ty).is_null()
101                    || !get_type_id::<PendingExpansionType>(ty).is_null()
102            } {
103                self.internal_type_escaped = true;
104                result = unsafe { (*self.builtin_types).errorType };
105            } else {
106                let genericty = unsafe { get_mutable_type_id::<GenericType>(result) };
107                if !genericty.is_null() {
108                    unsafe { (*genericty).scope = core::ptr::null_mut() };
109                }
110            }
111        }
112
113        result
114    }
115}