Skip to main content

luaur_analysis/functions/
check_frontend.rs

1use crate::enums::solver_mode::SolverMode;
2use crate::functions::check_non_strict::check_non_strict;
3use crate::functions::check_type_checker_2::check as check_type_checker_2;
4use crate::functions::freeze::freeze;
5use crate::functions::synthesize_export_return::synthesize_export_return;
6use crate::functions::unfreeze::unfreeze;
7use crate::records::builtin_types::BuiltinTypes;
8use crate::records::constraint_graph::ConstraintGraph;
9use crate::records::constraint_list::ConstraintList;
10use crate::records::data_flow_graph_builder::DataFlowGraphBuilder;
11use crate::records::dcr_logger::DcrLogger;
12use crate::records::file_resolver::FileResolver;
13use crate::records::frontend_options::FrontendOptions;
14use crate::records::internal_error_reporter::InternalErrorReporter;
15use crate::records::module::Module;
16use crate::records::module_resolver::ModuleResolver;
17use crate::records::normalizer::Normalizer;
18use crate::records::require_cycle::RequireCycle;
19use crate::records::source_module::SourceModule;
20use crate::records::stats::Stats;
21use crate::records::subtyping::Subtyping;
22use crate::records::type_check_limits::TypeCheckLimits;
23use crate::records::type_function_runtime::TypeFunctionRuntime;
24use crate::records::unifier_shared_state::UnifierSharedState;
25use crate::type_aliases::module_name_type::ModuleName;
26use crate::type_aliases::module_ptr_module::ModulePtr;
27use crate::type_aliases::scope_ptr_type::ScopePtr;
28use alloc::string::String;
29use alloc::sync::Arc;
30use alloc::vec::Vec;
31use core::ptr::NonNull;
32use luaur_ast::enums::mode::Mode;
33use luaur_common::records::dense_hash_map::DenseHashMap;
34use luaur_common::records::dense_hash_set::DenseHashSet;
35use luaur_common::{FFlag, FInt};
36use std::rc::Rc;
37
38pub fn check(
39    source_module: &SourceModule,
40    mode: Mode,
41    require_cycles: &[RequireCycle],
42    builtin_types: *mut BuiltinTypes,
43    ice_handler: *mut InternalErrorReporter,
44    module_resolver: *mut ModuleResolver,
45    _file_resolver: *mut FileResolver,
46    parent_scope: &ScopePtr,
47    type_function_scope: &ScopePtr,
48    prepare_module_scope: Rc<dyn Fn(&ModuleName, &ScopePtr)>,
49    options: FrontendOptions,
50    limits: TypeCheckLimits,
51    _record_json_log: bool,
52    stats: &mut Stats,
53    _write_json_log: Rc<dyn Fn(&ModuleName, String)>,
54) -> ModulePtr {
55    let module: ModulePtr = Arc::new(Module::default());
56    let module_ptr = Arc::as_ptr(&module) as *mut Module;
57
58    unsafe {
59        (*module_ptr).checked_in_new_solver = true;
60        (*module_ptr).name = source_module.name.clone();
61        (*module_ptr).human_readable_name = source_module.human_readable_name.clone();
62        (*module_ptr).mode = mode;
63        (*module_ptr).internal_types.owning_module = module_ptr;
64        (*module_ptr).interface_types.owning_module = module_ptr;
65        (*module_ptr).internal_types.collect_singleton_stats =
66            options.collect_type_allocation_stats;
67        (*module_ptr).allocator = Some(source_module.allocator.clone());
68        (*module_ptr).names = Some(source_module.names.clone());
69        (*module_ptr).root = source_module.root;
70        (*ice_handler).module_name = source_module.name.clone();
71    }
72
73    let mut dfg = unsafe {
74        DataFlowGraphBuilder::build(
75            source_module.root,
76            &mut (*module_ptr).def_arena,
77            &mut (*module_ptr).key_arena,
78            ice_handler,
79        )
80    };
81
82    let mut unifier_state = UnifierSharedState::unifier_shared_state(ice_handler);
83    unifier_state.counters.recursion_limit = FInt::LuauTypeInferRecursionLimit.get() as i32;
84    unifier_state.counters.iteration_limit = limits
85        .unifierIterationLimit()
86        .unwrap_or_else(|| FInt::LuauTypeInferIterationLimit.get() as i32);
87
88    let mut normalizer = unsafe {
89        Normalizer::new(
90            &mut (*module_ptr).internal_types,
91            builtin_types,
92            &mut unifier_state,
93            SolverMode::New,
94            false,
95        )
96    };
97
98    let mut type_function_runtime = TypeFunctionRuntime {
99        ice: unsafe { (*ice_handler).clone() },
100        limits: limits.clone(),
101        type_arena: crate::records::typed_allocator::TypedAllocator::default(),
102        type_pack_arena: crate::records::typed_allocator::TypedAllocator::default(),
103        state: (core::ptr::null_mut(), None),
104        initialized: DenseHashSet::new(core::ptr::null_mut()),
105        allow_evaluation: true,
106        root_scope: parent_scope.clone(),
107        messages: Vec::new(),
108        runtime_builder: core::ptr::null_mut(),
109    };
110
111    let mut cgraph_storage = if FFlag::LuauConstraintGraph.get() {
112        Some(ConstraintGraph {
113            builtin_types: NonNull::new(builtin_types).expect("builtinTypes must not be null"),
114            dependencies: DenseHashMap::new(Default::default()),
115            reverse_dependencies: DenseHashMap::new(Default::default()),
116            constraint_lists: Vec::<Box<ConstraintList>>::new(),
117        })
118    } else {
119        None
120    };
121    let cgraph = cgraph_storage
122        .as_mut()
123        .map(|cgraph| cgraph as *mut ConstraintGraph)
124        .unwrap_or(core::ptr::null_mut());
125
126    let mut subtyping = unsafe {
127        Subtyping::subtyping_owned(
128            builtin_types,
129            &mut (*module_ptr).internal_types,
130            &mut normalizer,
131            &mut type_function_runtime,
132            ice_handler,
133        )
134    };
135
136    let logger: *mut DcrLogger = core::ptr::null_mut();
137    let mut cg = crate::records::constraint_generator::ConstraintGenerator::constraint_generator(
138        module.clone(),
139        NonNull::new(&mut normalizer).unwrap(),
140        NonNull::new(&mut type_function_runtime).unwrap(),
141        NonNull::new(module_resolver).expect("moduleResolver must not be null"),
142        NonNull::new(builtin_types).expect("builtinTypes must not be null"),
143        NonNull::new(ice_handler).expect("iceHandler must not be null"),
144        parent_scope.clone(),
145        type_function_scope.clone(),
146        prepare_module_scope,
147        logger,
148        NonNull::new(&mut dfg).unwrap(),
149        require_cycles.to_vec(),
150        cgraph,
151    );
152
153    let constraint_set = cg.run(source_module.root);
154    unsafe {
155        (*module_ptr).errors = constraint_set.errors.clone();
156        (*module_ptr).constraint_generation_did_not_complete = cg.recursion_limit_met;
157    }
158
159    let mut cs =
160        crate::records::constraint_solver::ConstraintSolver::constraint_solver_not_null_normalizer_not_null_type_function_runtime_module_ptr_not_null_module_resolver_vector_require_cycle_dcr_logger_not_null_data_flow_graph_type_check_limits_constraint_graph_not_null_subtyping(
161            &normalizer,
162            &type_function_runtime,
163            module.clone(),
164            module_resolver,
165            require_cycles.to_vec(),
166            logger,
167            &dfg,
168            limits.clone(),
169            constraint_set,
170            cgraph,
171            &subtyping,
172        );
173
174    if let Some(seed) = options.randomize_constraint_resolution_seed {
175        cs.randomize(seed);
176    }
177
178    cs.constraint_solver_run();
179    stats.dynamic_constraints_created += cs.solver_constraints.len();
180
181    unsafe {
182        (*module_ptr).errors.extend(cs.errors.iter().cloned());
183        (*module_ptr).scopes = core::mem::take(&mut cg.scopes);
184        (*module_ptr).r#type = source_module.r#type;
185        (*module_ptr).upper_bound_contributors = core::mem::replace(
186            &mut cs.upper_bound_contributors,
187            DenseHashMap::new(core::ptr::null()),
188        );
189    }
190
191    if !unsafe { (*module_ptr).timeout || (*module_ptr).cancelled } {
192        match mode {
193            Mode::Nonstrict => {
194                check_non_strict(
195                    builtin_types,
196                    &mut type_function_runtime,
197                    ice_handler,
198                    &mut unifier_state,
199                    &dfg,
200                    &mut limits.clone(),
201                    source_module,
202                    module_ptr,
203                );
204            }
205            Mode::Definition | Mode::Strict => {
206                check_type_checker_2(
207                    builtin_types,
208                    &mut type_function_runtime,
209                    &mut unifier_state,
210                    &mut limits.clone(),
211                    logger,
212                    source_module,
213                    module_ptr,
214                );
215            }
216            Mode::NoCheck => {}
217        }
218
219        if FFlag::LuauExportValueSyntax.get()
220            && FFlag::LuauExportValueTypecheck.get()
221            && !unsafe { (*module_ptr).timeout || (*module_ptr).cancelled }
222        {
223            synthesize_export_return(builtin_types, module_ptr);
224        }
225    }
226
227    unsafe {
228        if (*module_ptr).errors.len() == 1
229            && !FFlag::DebugLuauAlwaysShowConstraintSolvingIncomplete.get()
230            && matches!(
231                &(&(*module_ptr).errors)[0].data,
232                crate::type_aliases::type_error_data::TypeErrorData::ConstraintSolvingIncompleteError(_)
233            )
234        {
235            (*module_ptr).errors.clear();
236        }
237
238        unfreeze(&mut (*module_ptr).interface_types);
239        (*module_ptr).clone_public_interface(builtin_types, &mut *ice_handler, SolverMode::New);
240        freeze(&mut (*module_ptr).internal_types);
241        freeze(&mut (*module_ptr).interface_types);
242    }
243
244    module
245}