Skip to main content

luaur_analysis/methods/
constraint_solver_resolve_module.rs

1use crate::enums::type_file_resolver::Type;
2use crate::functions::first::first;
3use crate::functions::get_type_pack::get_type_pack_id;
4use crate::records::constraint_solver::ConstraintSolver;
5use crate::records::illegal_require::IllegalRequire;
6use crate::records::module_info::ModuleInfo;
7use crate::records::unknown_require::UnknownRequire;
8use crate::type_aliases::error_type_pack::ErrorTypePack;
9use crate::type_aliases::type_error_data::TypeErrorData;
10use crate::type_aliases::type_id::TypeId;
11use alloc::string::{String, ToString};
12use luaur_ast::records::location::Location;
13
14impl ConstraintSolver {
15    pub fn resolve_module(&mut self, info: &ModuleInfo, location: &Location) -> TypeId {
16        if info.name.is_empty() {
17            self.report_error_type_error_data_location(
18                UnknownRequire::new(String::new()).into(),
19                location,
20            );
21            return unsafe { (*self.builtin_types).errorType };
22        }
23
24        for require_cycle in &self.require_cycles {
25            if !require_cycle.path.is_empty() && require_cycle.path[0] == info.name {
26                return unsafe { (*self.builtin_types).anyType };
27            }
28        }
29
30        let module = unsafe {
31            ((*self.module_resolver).vtable.get_module)(self.module_resolver, &info.name)
32        };
33        if module.is_none() {
34            if unsafe {
35                !((*self.module_resolver).vtable.module_exists)(self.module_resolver, &info.name)
36            } && !info.optional
37            {
38                let human_readable_name = unsafe {
39                    ((*self.module_resolver)
40                        .vtable
41                        .get_human_readable_module_name)(
42                        self.module_resolver, &info.name
43                    )
44                };
45                self.report_error_type_error_data_location(
46                    UnknownRequire::new(human_readable_name).into(),
47                    location,
48                );
49            }
50            return unsafe { (*self.builtin_types).errorType };
51        }
52
53        let module = module.unwrap();
54        if module.r#type != Type::Module {
55            self.report_error_type_error_data_location(
56                IllegalRequire::new(
57                    module.human_readable_name.clone(),
58                    "Module is not a ModuleScript. It cannot be required.".to_string(),
59                )
60                .into(),
61                location,
62            );
63            return unsafe { (*self.builtin_types).errorType };
64        }
65
66        if module
67            .errors
68            .iter()
69            .any(|error| matches!(error.data, TypeErrorData::SyntaxError(_)))
70        {
71            return unsafe { (*self.builtin_types).errorType };
72        }
73
74        let module_pack = module.return_type;
75        if !unsafe { get_type_pack_id::<ErrorTypePack>(module_pack) }.is_null() {
76            return unsafe { (*self.builtin_types).errorType };
77        }
78
79        let module_type = first(module_pack, true);
80        if module_type.is_none() {
81            self.report_error_type_error_data_location(
82                IllegalRequire::new(
83                    module.human_readable_name.clone(),
84                    "Module does not return exactly 1 value. It cannot be required.".to_string(),
85                )
86                .into(),
87                location,
88            );
89            return unsafe { (*self.builtin_types).errorType };
90        }
91
92        module_type.unwrap()
93    }
94}