luaur_analysis/methods/
magic_clone_infer.rs1use crate::functions::as_mutable_type_pack_alt_d::as_mutable_type_pack;
2use crate::functions::flatten_type_pack::flatten_type_pack_id;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_mutable_type::get_mutable_type_id;
5use crate::functions::get_type_alt_j::get_type_id;
6use crate::functions::shallow_clone_clone_alt_b::shallow_clone;
7use crate::functions::track_interior_free_type::track_interior_free_type;
8use crate::records::clone_state::CloneState;
9use crate::records::count_mismatch::CountMismatch;
10use crate::records::magic_function_call_context::MagicFunctionCallContext;
11use crate::records::table_type::TableType;
12use crate::records::type_pack::TypePack;
13use crate::type_aliases::type_error_data::TypeErrorData;
14use crate::type_aliases::type_pack_variant::TypePackVariant;
15use alloc::vec;
16use luaur_common::records::dense_hash_map::DenseHashMap;
17
18pub fn magic_clone_infer(context: &MagicFunctionCallContext) -> bool {
19 let solver = unsafe { context.solver.as_ref() };
20 let arena = unsafe { &mut *solver.arena };
21 let call_site = unsafe { context.call_site.as_ref() };
22
23 let (param_types, _param_tail) = flatten_type_pack_id(context.arguments);
24 if param_types.is_empty() || call_site.args.size == 0 {
25 unsafe {
26 (*context.solver.as_ptr()).report_error_type_error_data_location(
27 TypeErrorData::CountMismatch(CountMismatch {
28 expected: 1,
29 actual: 0,
30 ..Default::default()
31 }),
32 &call_site.arg_location,
33 );
34 }
35 return false;
36 }
37
38 let input_type = unsafe { follow_type_id(param_types[0]) };
39
40 if unsafe { get_type_id::<TableType>(input_type) }.is_null() {
41 return false;
42 }
43
44 let mut clone_state = CloneState {
45 builtin_types: solver.builtin_types,
46 seen_types: DenseHashMap::new(core::ptr::null()),
47 seen_type_packs: DenseHashMap::new(core::ptr::null()),
48 };
49 let result_type = shallow_clone(
50 input_type,
51 arena,
52 &mut clone_state,
53 true,
54 );
55
56 let constraint_scope = unsafe { (*context.constraint.as_ptr()).scope };
57
58 let table_type = unsafe { get_mutable_type_id::<TableType>(result_type) };
59 if !table_type.is_null() {
60 unsafe {
61 (*table_type).scope = constraint_scope;
62 }
63 }
64
65 track_interior_free_type(constraint_scope, result_type);
66
67 let cloned_type_pack = arena.add_type_pack_t(TypePack {
68 head: vec![result_type],
69 tail: None,
70 });
71 let result_mut = as_mutable_type_pack(context.result);
72 unsafe {
73 (*result_mut).ty = TypePackVariant::Bound(cloned_type_pack);
74 }
75
76 true
77}