Skip to main content

luaur_analysis/methods/
magic_format_handle_old_solver.rs

1use crate::functions::flatten_type_pack::flatten_type_pack_id;
2use crate::functions::parse_format_string::parse_format_string;
3use crate::records::count_mismatch::CountMismatch;
4use crate::records::type_arena::TypeArena;
5use crate::records::type_checker::TypeChecker;
6use crate::records::type_error::TypeError;
7use crate::records::with_predicate::WithPredicate;
8use crate::type_aliases::scope_ptr_type_infer::ScopePtr;
9use crate::type_aliases::type_id::TypeId;
10use crate::type_aliases::type_pack_id::TypePackId;
11use alloc::vec::Vec;
12use luaur_ast::records::ast_expr_call::AstExprCall;
13use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
14use luaur_ast::records::ast_expr_group::AstExprGroup;
15use luaur_ast::records::ast_expr_index_name::AstExprIndexName;
16use luaur_ast::records::location::Location;
17use luaur_ast::rtti::ast_node_as;
18
19pub fn magic_format_handle_old_solver(
20    typechecker: &mut TypeChecker,
21    scope: &ScopePtr,
22    expr: &AstExprCall,
23    with_predicate: WithPredicate<TypePackId>,
24) -> Option<WithPredicate<TypePackId>> {
25    let (param_pack, _predicates) = (with_predicate.r#type, with_predicate.predicates);
26
27    let module = typechecker.current_module.as_ref()?;
28    let arena = unsafe {
29        &mut (*(std::sync::Arc::as_ptr(module) as *mut crate::records::module::Module))
30            .internal_types
31    };
32
33    let mut fmt: *mut AstExprConstantString = core::ptr::null_mut();
34
35    if expr.self_ {
36        let index = unsafe {
37            ast_node_as::<AstExprIndexName>(expr.func as *mut luaur_ast::records::ast_node::AstNode)
38        };
39        if !index.is_null() {
40            let group = unsafe {
41                ast_node_as::<AstExprGroup>(
42                    (*index).expr as *mut luaur_ast::records::ast_node::AstNode,
43                )
44            };
45            if !group.is_null() {
46                fmt = unsafe {
47                    ast_node_as::<AstExprConstantString>(
48                        (*group).expr as *mut luaur_ast::records::ast_node::AstNode,
49                    )
50                };
51            } else {
52                fmt = unsafe {
53                    ast_node_as::<AstExprConstantString>(
54                        (*index).expr as *mut luaur_ast::records::ast_node::AstNode,
55                    )
56                };
57            }
58        }
59    }
60
61    if !expr.self_ && expr.args.size > 0 {
62        fmt = unsafe {
63            ast_node_as::<AstExprConstantString>(
64                unsafe { *expr.args.data.add(0) } as *mut luaur_ast::records::ast_node::AstNode
65            )
66        };
67    }
68
69    if fmt.is_null() {
70        return None;
71    }
72
73    let expected: Vec<TypeId> = unsafe {
74        parse_format_string(
75            core::ptr::NonNull::new_unchecked(typechecker.builtin_types),
76            (*fmt).value.data,
77            (*fmt).value.size,
78        )
79    };
80
81    let (params, tail) = flatten_type_pack_id(param_pack);
82
83    let param_offset: usize = 1;
84    let data_offset: usize = if expr.self_ { 0 } else { 1 };
85
86    for i in 0..expected.len() {
87        if i + param_offset >= params.len() {
88            break;
89        }
90
91        let arg_index = std::cmp::min(i + data_offset, expr.args.size as usize - 1);
92        let location = unsafe { &(*(*expr.args.data.add(arg_index as usize))).base.location };
93
94        typechecker.unify_type_id_type_id_scope_ptr_location(
95            params[i + param_offset],
96            expected[i],
97            scope,
98            location,
99        );
100    }
101
102    let num_actual_params = params.len();
103    let num_expected_params = expected.len() + 1;
104
105    if num_expected_params != num_actual_params
106        && (!tail.is_some() || num_expected_params < num_actual_params)
107    {
108        let error = TypeError::type_error_location_type_error_data(
109            expr.base.base.location,
110            crate::records::type_error_data::TypeErrorData::CountMismatch(CountMismatch {
111                expected: num_expected_params,
112                maximum: None,
113                actual: num_actual_params,
114                context: crate::records::count_mismatch::CountMismatchContext::Arg,
115                is_variadic: false,
116                function: String::new(),
117            }),
118        );
119        typechecker.report_error_type_error(&error);
120    }
121
122    Some(WithPredicate::with_predicate_t(
123        arena.add_type_pack_initializer_list_type_id(&[typechecker.string_type]),
124    ))
125}