Skip to main content

luaur_analysis/methods/
magic_select_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::records::generic_error::GenericError;
4use crate::records::magic_function_call_context::MagicFunctionCallContext;
5use crate::records::type_error::TypeError;
6use crate::type_aliases::type_error_data::TypeErrorData;
7use crate::type_aliases::type_id::TypeId;
8use crate::type_aliases::type_pack_variant::TypePackVariant;
9use alloc::string::ToString;
10use alloc::vec::Vec;
11use luaur_ast::records::ast_expr_constant_number::AstExprConstantNumber;
12use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
13use luaur_ast::records::ast_node::AstNode;
14use luaur_ast::rtti::ast_node_as;
15
16pub fn magic_select_infer(context: &MagicFunctionCallContext) -> bool {
17    let solver = unsafe { context.solver.as_ref() };
18    let call_site = unsafe { context.call_site.as_ref() };
19
20    if call_site.args.size <= 0 {
21        let error = TypeError::type_error_location_type_error_data(
22            call_site.base.base.location,
23            TypeErrorData::GenericError(GenericError::new(
24                "select should take 1 or more arguments".to_string(),
25            )),
26        );
27        unsafe {
28            (*context.solver.as_ptr()).report_error_type_error(error);
29        }
30        return false;
31    }
32
33    let arg1 = unsafe { *call_site.args.data.add(0) };
34
35    let num = unsafe { ast_node_as::<AstExprConstantNumber>(arg1 as *mut AstNode) };
36    if !num.is_null() {
37        let (v, tail) = flatten_type_pack_id(context.arguments);
38
39        let offset = unsafe { (*num).value } as i32;
40        if offset > 0 {
41            let offset_usize = offset as usize;
42            if offset_usize < v.len() {
43                let res: Vec<TypeId> = v[offset_usize..].to_vec();
44                let res_type_pack = unsafe { &mut *solver.arena }
45                    .add_type_pack_vector_type_id_optional_type_pack_id(res, tail);
46                let result_mut = as_mutable_type_pack(context.result);
47                unsafe {
48                    (*result_mut).ty = TypePackVariant::Bound(res_type_pack);
49                }
50            } else if let Some(tail) = tail {
51                let result_mut = as_mutable_type_pack(context.result);
52                unsafe {
53                    (*result_mut).ty = TypePackVariant::Bound(tail);
54                }
55            }
56
57            return true;
58        }
59
60        return false;
61    }
62
63    let str_expr = unsafe { ast_node_as::<AstExprConstantString>(arg1 as *mut AstNode) };
64    if !str_expr.is_null()
65        && unsafe { (*str_expr).value.size } == 1
66        && unsafe { *(*str_expr).value.data } == b'#' as core::ffi::c_char
67    {
68        let number_type_pack = unsafe { &mut *solver.arena }
69            .add_type_pack_initializer_list_type_id(
70                &[unsafe { &*solver.builtin_types }.numberType],
71            );
72        let result_mut = as_mutable_type_pack(context.result);
73        unsafe {
74            (*result_mut).ty = TypePackVariant::Bound(number_type_pack);
75        }
76        return true;
77    }
78
79    false
80}