luaur_analysis/methods/
magic_gmatch_infer.rs1use 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::parse_pattern_string::parse_pattern_string;
4use crate::records::function_type::FunctionType;
5use crate::records::magic_function_call_context::MagicFunctionCallContext;
6use crate::records::magic_gmatch::MagicGmatch;
7use crate::records::type_pack::TypePack;
8use crate::type_aliases::type_pack_variant::TypePackVariant;
9use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
10use luaur_ast::records::ast_node::AstNode;
11use luaur_ast::rtti::ast_node_as;
12
13impl MagicGmatch {
14 pub fn infer(&self, context: &MagicFunctionCallContext) -> bool {
15 let (params, _tail) = flatten_type_pack_id(context.arguments);
16
17 if params.len() != 2 {
18 return false;
19 }
20
21 let solver = unsafe { context.solver.as_ref() };
22 let arena = unsafe { &mut *solver.arena };
23 let call_site = unsafe { context.call_site.as_ref() };
24
25 let index = if call_site.self_ { 0 } else { 1 };
26 let pattern = if call_site.args.size > index {
27 let expr = unsafe { *call_site.args.data.add(index) };
28 unsafe { ast_node_as::<AstExprConstantString>(expr as *mut AstNode) }
29 } else {
30 core::ptr::null_mut()
31 };
32
33 if pattern.is_null() {
34 return false;
35 }
36
37 let return_types = unsafe {
38 let pattern = &*pattern;
39 parse_pattern_string(
40 core::ptr::NonNull::new_unchecked(solver.builtin_types),
41 pattern.value.data,
42 pattern.value.size,
43 )
44 };
45
46 if return_types.is_empty() {
47 return false;
48 }
49
50 unsafe {
51 let builtin_types = &*solver.builtin_types;
52 (*context.solver.as_ptr()).constraint_solver_unify(
53 context.constraint.as_ptr(),
54 params[0],
55 builtin_types.stringType,
56 );
57 }
58
59 let empty_pack = arena.add_type_pack_t(TypePack {
60 head: Vec::new(),
61 tail: None,
62 });
63 let return_list = arena.add_type_pack_t(TypePack {
64 head: return_types,
65 tail: None,
66 });
67 let iterator_type = arena.add_type(FunctionType::function_type_new(
68 empty_pack,
69 return_list,
70 None,
71 false,
72 ));
73 let res_type_pack = arena.add_type_pack_t(TypePack {
74 head: vec![iterator_type],
75 tail: None,
76 });
77
78 let result_mut = as_mutable_type_pack(context.result);
79 unsafe {
80 (*result_mut).ty = TypePackVariant::Bound(res_type_pack);
81 }
82
83 true
84 }
85}