luaur_analysis/methods/
magic_format_handle_old_solver.rs1use 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}