Skip to main content

luaur_analysis/methods/
magic_pack_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::get_type_pack::get_type_pack_id;
4use crate::functions::reduce_union::reduce_union;
5use crate::records::magic_function_call_context::MagicFunctionCallContext;
6use crate::records::property_type::Property;
7use crate::records::table_indexer::TableIndexer;
8use crate::records::table_type::TableType;
9use crate::records::type_pack::TypePack;
10use crate::records::union_type::UnionType;
11use crate::records::variadic_type_pack::VariadicTypePack;
12use crate::type_aliases::props_type::Props;
13use crate::type_aliases::type_id::TypeId;
14use crate::type_aliases::type_pack_variant::TypePackVariant;
15use alloc::vec;
16use alloc::vec::Vec;
17
18pub fn magic_pack_infer(context: &MagicFunctionCallContext) -> bool {
19    let solver = unsafe { context.solver.as_ref() };
20    let arena = unsafe { &mut *solver.arena };
21    let builtin_types = unsafe { &*solver.builtin_types };
22
23    let (param_types, param_tail) = flatten_type_pack_id(context.arguments);
24
25    let mut options: Vec<TypeId> = Vec::new();
26    options.reserve(param_types.len());
27    for ty in param_types {
28        options.push(ty);
29    }
30
31    if let Some(param_tail) = param_tail {
32        let vtp = unsafe { get_type_pack_id::<VariadicTypePack>(param_tail) };
33        if !vtp.is_null() {
34            options.push(unsafe { (*vtp).ty });
35        }
36    }
37
38    let options = reduce_union(&options);
39
40    let result = if options.is_empty() {
41        builtin_types.nilType
42    } else if options.len() == 1 {
43        options[0]
44    } else {
45        arena.add_type(UnionType { options })
46    };
47
48    let number_type = builtin_types.numberType;
49    let mut props = Props::default();
50    props.insert("n".to_string(), Property::rw_type_id(number_type));
51
52    let packed_table = arena.add_type(TableType {
53        props,
54        indexer: Some(TableIndexer {
55            index_type: number_type,
56            index_result_type: result,
57            is_read_only: false,
58        }),
59        state: crate::enums::table_state::TableState::Sealed,
60        level: crate::records::type_level::TypeLevel::default(),
61        scope: core::ptr::null_mut(),
62        name: None,
63        synthetic_name: None,
64        instantiated_type_params: Vec::new(),
65        instantiated_type_pack_params: Vec::new(),
66        definition_module_name: Default::default(),
67        definition_location: Default::default(),
68        bound_to: None,
69        tags: Default::default(),
70        remaining_props: 0,
71    });
72
73    let table_type_pack = arena.add_type_pack_t(TypePack {
74        head: vec![packed_table],
75        tail: None,
76    });
77    let result_mut = as_mutable_type_pack(context.result);
78    unsafe {
79        (*result_mut).ty = TypePackVariant::Bound(table_type_pack);
80    }
81
82    true
83}