Skip to main content

luaur_analysis/methods/
magic_clone_infer.rs

1use 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        /* ignorePersistent */ 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}