Skip to main content

luaur_analysis/methods/
module_clone_public_interface.rs

1use crate::enums::solver_mode::SolverMode;
2use crate::records::builtin_types::BuiltinTypes;
3use crate::records::clone_public_interface::ClonePublicInterface;
4use crate::records::clone_state::CloneState;
5use crate::records::internal_error::InternalError;
6use crate::records::internal_error_reporter::InternalErrorReporter;
7use crate::records::module::Module;
8use crate::records::scope::Scope;
9use crate::records::txn_log::TxnLog;
10use crate::records::type_error::TypeError;
11use crate::type_aliases::type_pack_id::TypePackId;
12use alloc::sync::Arc;
13use alloc::vec::Vec;
14use luaur_ast::records::location::Location;
15use luaur_common::records::dense_hash_map::DenseHashMap;
16
17impl Module {
18    /// `void Module::clonePublicInterface(NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice, SolverMode mode)`.
19    /// Reference: `Module.cpp:299-348`.
20    pub fn clone_public_interface(
21        &mut self,
22        builtin_types: *mut BuiltinTypes,
23        _ice: &mut InternalErrorReporter,
24        mode: SolverMode,
25    ) {
26        // C++ `CloneState cloneState{builtinTypes};` — declared (parity) but the
27        // interface clone is driven by `ClonePublicInterface`'s own substitution.
28        let _clone_state = CloneState {
29            builtin_types,
30            seen_types: DenseHashMap::new(core::ptr::null()),
31            seen_type_packs: DenseHashMap::new(core::ptr::null()),
32        };
33
34        let module_scope = self.get_module_scope();
35        // The C++ mutates the Scope behind the shared_ptr; mirror that by taking a
36        // raw pointer to the aliased Scope object.
37        let module_scope_ptr = Arc::as_ptr(&module_scope) as *mut Scope;
38
39        let return_type: TypePackId = unsafe { (*module_scope_ptr).return_type };
40        let varargpack: Option<TypePackId> = if mode == SolverMode::New {
41            None
42        } else {
43            unsafe { (*module_scope_ptr).vararg_pack }
44        };
45
46        // C++ `TxnLog log;` — a fresh, empty transaction log.
47        let log = TxnLog {
48            type_var_changes: DenseHashMap::new(core::ptr::null()),
49            type_pack_changes: DenseHashMap::new(core::ptr::null()),
50            parent: core::ptr::null_mut(),
51            owned_seen: Vec::new(),
52            shared_seen: core::ptr::null_mut(),
53            radioactive: false,
54        };
55        let mut clone_public_interface =
56            ClonePublicInterface::new(&log, builtin_types, self as *mut Module, mode);
57
58        let return_type = clone_public_interface.clone_type_pack(return_type);
59
60        unsafe { (*module_scope_ptr).return_type = return_type };
61        if let Some(vp) = varargpack {
62            let varargpack = clone_public_interface.clone_type_pack(vp);
63            unsafe { (*module_scope_ptr).vararg_pack = Some(varargpack) };
64        }
65
66        unsafe {
67            for (_name, tf) in (*module_scope_ptr).exported_type_bindings.iter_mut() {
68                let cloned = clone_public_interface.clone_type_fun(&*tf);
69                *tf = cloned;
70            }
71        }
72
73        for (_name, ty) in self.declared_globals.iter_mut() {
74            *ty = clone_public_interface.clone_type(*ty);
75        }
76
77        for tf in self.type_function_aliases.iter_mut() {
78            let cloned = clone_public_interface.clone_type_fun(&**tf);
79            **tf = cloned;
80        }
81
82        if clone_public_interface.internal_type_escaped {
83            self.errors
84                .push(TypeError::type_error_location_module_name_type_error_data(
85                    // Not amazing but the best we can do.
86                    Location::default(),
87                    self.name.clone(),
88                    InternalError::new(alloc::string::String::from(
89                        "An internal type is escaping this module; please report this bug at \
90                     https://github.com/luau-lang/luau/issues",
91                    ))
92                    .into(),
93                ));
94        }
95
96        // Copy external stuff over to Module itself
97        self.return_type = unsafe { (*module_scope_ptr).return_type };
98        self.exported_type_bindings = unsafe { (*module_scope_ptr).exported_type_bindings.clone() };
99    }
100}