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            // Empty; lazily owns a box on first `push_seen` (freed on drop).
53            shared_seen: core::ptr::null_mut(),
54            owned_seen_box: None,
55            radioactive: false,
56        };
57        let mut clone_public_interface =
58            ClonePublicInterface::new(&log, builtin_types, self as *mut Module, mode);
59
60        let return_type = clone_public_interface.clone_type_pack(return_type);
61
62        unsafe { (*module_scope_ptr).return_type = return_type };
63        if let Some(vp) = varargpack {
64            let varargpack = clone_public_interface.clone_type_pack(vp);
65            unsafe { (*module_scope_ptr).vararg_pack = Some(varargpack) };
66        }
67
68        unsafe {
69            for (_name, tf) in (*module_scope_ptr).exported_type_bindings.iter_mut() {
70                let cloned = clone_public_interface.clone_type_fun(&*tf);
71                *tf = cloned;
72            }
73        }
74
75        for (_name, ty) in self.declared_globals.iter_mut() {
76            *ty = clone_public_interface.clone_type(*ty);
77        }
78
79        for tf in self.type_function_aliases.iter_mut() {
80            let cloned = clone_public_interface.clone_type_fun(&**tf);
81            **tf = cloned;
82        }
83
84        if clone_public_interface.internal_type_escaped {
85            self.errors
86                .push(TypeError::type_error_location_module_name_type_error_data(
87                    // Not amazing but the best we can do.
88                    Location::default(),
89                    self.name.clone(),
90                    InternalError::new(alloc::string::String::from(
91                        "An internal type is escaping this module; please report this bug at \
92                     https://github.com/luau-lang/luau/issues",
93                    ))
94                    .into(),
95                ));
96        }
97
98        // Copy external stuff over to Module itself
99        self.return_type = unsafe { (*module_scope_ptr).return_type };
100        self.exported_type_bindings = unsafe { (*module_scope_ptr).exported_type_bindings.clone() };
101    }
102}