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 if expr.args.size == 0 {
94 break;
95 }
96
97 let arg_index = std::cmp::min(i + data_offset, expr.args.size as usize - 1);
98 let location = unsafe { &(*(*expr.args.data.add(arg_index as usize))).base.location };
99
100 typechecker.unify_type_id_type_id_scope_ptr_location(
101 params[i + param_offset],
102 expected[i],
103 scope,
104 location,
105 );
106 }
107
108 let num_actual_params = params.len();
109 let num_expected_params = expected.len() + 1;
110
111 if num_expected_params != num_actual_params
112 && (!tail.is_some() || num_expected_params < num_actual_params)
113 {
114 let error = TypeError::type_error_location_type_error_data(
115 expr.base.base.location,
116 crate::records::type_error_data::TypeErrorData::CountMismatch(CountMismatch {
117 expected: num_expected_params,
118 maximum: None,
119 actual: num_actual_params,
120 context: crate::records::count_mismatch::CountMismatchContext::Arg,
121 is_variadic: false,
122 function: String::new(),
123 }),
124 );
125 typechecker.report_error_type_error(&error);
126 }
127
128 Some(WithPredicate::with_predicate_t(
129 arena.add_type_pack_initializer_list_type_id(&[typechecker.string_type]),
130 ))
131}