luaur_analysis/methods/
frontend_check_build_queue_item.rs1use crate::enums::solver_mode::SolverMode;
2use crate::functions::apply_internal_limit_scaling::apply_internal_limit_scaling;
3use crate::functions::copy_errors::copy_errors;
4use crate::functions::filter_lint_options::filter_lint_options;
5use crate::functions::freeze::freeze;
6use crate::functions::get_timestamp::get_timestamp;
7use crate::functions::lint::lint;
8use crate::functions::make_type_check_limits::make_type_check_limits;
9use crate::functions::unfreeze::unfreeze;
10use crate::records::build_queue_item::BuildQueueItem;
11use crate::records::frontend::Frontend;
12use crate::records::module::Module;
13use crate::records::module_has_cyclic_dependency::ModuleHasCyclicDependency;
14use crate::records::source_node::SourceNode;
15use crate::records::syntax_error::SyntaxError;
16use crate::records::type_error::TypeError;
17use crate::type_aliases::type_error_data::TypeErrorData;
18use alloc::sync::Arc;
19use alloc::vec::Vec;
20use luaur_ast::enums::mode::Mode;
21use luaur_common::macros::luau_timetrace_scope::LUAU_TIMETRACE_SCOPE;
22use luaur_common::FFlag;
23use luaur_common::FInt;
24
25impl Frontend {
26 pub fn check_build_queue_item(&mut self, item: &mut BuildQueueItem) {
27 let source_node_ptr = Arc::as_ptr(&item.source_node) as *mut SourceNode;
31
32 let mode: Mode = if FFlag::DebugLuauForceStrictMode.get() {
33 Mode::Strict
34 } else if FFlag::DebugLuauForceNonStrictMode.get() {
35 Mode::Nonstrict
36 } else {
37 item.source_module.mode.unwrap_or(item.config.mode)
38 };
39
40 unsafe {
41 let source_module_ptr = Arc::as_ptr(&item.source_module)
42 as *mut crate::records::source_module::SourceModule;
43 (*source_module_ptr).mode = Some(mode);
44 }
45
46 let environment_scope = item.environment_scope.clone();
47 let timestamp = get_timestamp();
48 let require_cycles = item.require_cycles.clone();
49
50 let mut type_check_limits = make_type_check_limits(&item.options);
51
52 if item.options.apply_internal_limit_scaling {
54 let autocomplete_mult = unsafe { (*source_node_ptr).autocomplete_limits_mult };
55
56 if FInt::LuauTarjanChildLimit.get() > 0 {
57 type_check_limits.instantiationChildLimit = Some(
58 1.max((FInt::LuauTarjanChildLimit.get() as f64 * autocomplete_mult) as i32),
59 );
60 } else {
61 type_check_limits.instantiationChildLimit = None;
62 }
63
64 if FInt::LuauTypeInferIterationLimit.get() > 0 {
65 type_check_limits.unifierIterationLimit = Some(1.max(
66 (FInt::LuauTypeInferIterationLimit.get() as f64 * autocomplete_mult) as i32,
67 ));
68 } else {
69 type_check_limits.unifierIterationLimit = None;
70 }
71 }
72
73 if item.options.for_autocomplete {
74 let module_for_autocomplete = self.check_source_module_mode_vector_require_cycle_optional_scope_ptr_bool_bool_frontend_stats_type_check_limits(
76 &item.source_module,
77 Mode::Strict,
78 require_cycles,
79 Some(environment_scope.clone()),
80 true,
81 false,
82 &mut item.stats,
83 type_check_limits,
84 );
85
86 let duration = get_timestamp() - timestamp;
87 let module_ptr = Arc::as_ptr(&module_for_autocomplete) as *mut Module;
88 unsafe {
89 (*module_ptr).check_duration_sec = duration;
90 }
91
92 self.populate_expected_types(&item.source_module, module_ptr, &environment_scope);
93
94 if item.options.module_time_limit_sec.is_some()
95 && item.options.apply_internal_limit_scaling
96 {
97 apply_internal_limit_scaling(
98 unsafe { &mut *source_node_ptr },
99 module_for_autocomplete.clone(),
100 item.options.module_time_limit_sec.unwrap(),
101 );
102 }
103
104 item.stats.time_check += duration;
105 item.stats.files_strict += 1;
106
107 if item.options.collect_type_allocation_stats {
108 let m = &*module_for_autocomplete;
109 item.stats.types_allocated += m.internal_types.types.size();
110 item.stats.type_packs_allocated += m.internal_types.type_packs.size();
111 item.stats.bool_singletons_minted += m.internal_types.bool_singletons_minted;
112 item.stats.str_singletons_minted += m.internal_types.str_singletons_minted;
113 item.stats.unique_str_singletons_minted +=
114 m.internal_types.unique_str_singletons_minted.size();
115 }
116
117 if let Some(custom_module_check) = item.options.custom_module_check {
118 custom_module_check(&item.source_module, &module_for_autocomplete);
119 }
120
121 item.module = module_for_autocomplete;
122 return;
123 }
124
125 let module = self.check_source_module_mode_vector_require_cycle_optional_scope_ptr_bool_bool_frontend_stats_type_check_limits(
126 &item.source_module,
127 mode,
128 require_cycles.clone(),
129 Some(environment_scope.clone()),
130 false,
131 item.record_json_log,
132 &mut item.stats,
133 type_check_limits,
134 );
135
136 let duration = get_timestamp() - timestamp;
137 let module_ptr: *mut Module = Arc::as_ptr(&module) as *mut Module;
138 unsafe {
139 (*module_ptr).check_duration_sec = duration;
140 }
141
142 self.populate_expected_types(&item.source_module, module_ptr, &environment_scope);
143
144 if item.options.module_time_limit_sec.is_some() && item.options.apply_internal_limit_scaling
145 {
146 apply_internal_limit_scaling(
147 unsafe { &mut *source_node_ptr },
148 module.clone(),
149 item.options.module_time_limit_sec.unwrap(),
150 );
151 }
152
153 item.stats.time_check += duration;
154 item.stats.files_strict += if mode == Mode::Strict { 1 } else { 0 };
155 item.stats.files_nonstrict += if mode == Mode::Nonstrict { 1 } else { 0 };
156
157 if item.options.collect_type_allocation_stats {
158 let m = &*module;
159 item.stats.types_allocated += m.internal_types.types.size();
160 item.stats.type_packs_allocated += m.internal_types.type_packs.size();
161 item.stats.bool_singletons_minted += m.internal_types.bool_singletons_minted;
162 item.stats.str_singletons_minted += m.internal_types.str_singletons_minted;
163 item.stats.unique_str_singletons_minted +=
164 m.internal_types.unique_str_singletons_minted.size();
165 }
166
167 if let Some(custom_module_check) = item.options.custom_module_check {
168 custom_module_check(&item.source_module, &module);
169 }
170
171 if self.get_luau_solver_mode() == SolverMode::New && mode == Mode::NoCheck {
172 unsafe {
173 (*module_ptr).errors.clear();
174 }
175 }
176
177 if item.options.run_lint_checks {
178 LUAU_TIMETRACE_SCOPE!("lint", "Frontend");
179
180 let mut lint_options = item
181 .options
182 .enabled_lint_warnings
183 .clone()
184 .unwrap_or(item.config.enabled_lint);
185 filter_lint_options(&mut lint_options, &item.source_module.hotcomments, mode);
186
187 let lint_timestamp = get_timestamp();
188
189 let warnings = lint(
190 item.source_module.root as *mut luaur_ast::records::ast_stat::AstStat,
191 item.source_module.names.as_ref(),
192 &environment_scope,
193 module_ptr as *const Module,
194 &item.source_module.hotcomments,
195 &lint_options,
196 );
197
198 item.stats.time_lint += get_timestamp() - lint_timestamp;
199
200 let lint_result = self.classify_lints(&warnings, &item.config);
201 unsafe {
202 (*module_ptr).lint_result = lint_result;
203 }
204 }
205
206 if !item.options.retain_full_type_graphs {
207 unsafe {
210 unfreeze(&mut (*module_ptr).interface_types);
211 let mut errors = core::mem::take(&mut (*module_ptr).errors);
213 copy_errors(
214 &mut errors,
215 &mut (*module_ptr).interface_types,
216 &*self.builtin_types,
217 );
218 (*module_ptr).errors = errors;
219 freeze(&mut (*module_ptr).interface_types);
220
221 (*module_ptr).internal_types.clear();
222 (*module_ptr).def_arena.allocator.clear();
223 (*module_ptr).key_arena.allocator.clear();
224
225 (*module_ptr).ast_types.clear();
226 (*module_ptr).ast_type_packs.clear();
227 (*module_ptr).ast_expected_types.clear();
228 (*module_ptr).ast_original_call_types.clear();
229 (*module_ptr).ast_overload_resolved_types.clear();
230 (*module_ptr).ast_for_in_next_types.clear();
231 (*module_ptr).ast_resolved_types.clear();
232 (*module_ptr).ast_resolved_type_packs.clear();
233 (*module_ptr).ast_compound_assign_result_types.clear();
234 (*module_ptr).ast_scopes.clear();
235 (*module_ptr).upper_bound_contributors.clear();
236 (*module_ptr).scopes.clear();
237 }
238 }
239
240 if mode != Mode::NoCheck {
241 for cyc in &require_cycles {
242 let te = TypeError {
243 location: cyc.location,
244 module_name: item.name.clone(),
245 data: TypeErrorData::ModuleHasCyclicDependency(ModuleHasCyclicDependency::new(
246 cyc.path.clone(),
247 )),
248 };
249 unsafe {
250 (*module_ptr).errors.push(te);
251 }
252 }
253 }
254
255 let mut parse_errors: Vec<TypeError> = Vec::new();
256 for pe in &item.source_module.parse_errors {
257 parse_errors.push(TypeError {
258 location: *pe.get_location(),
259 module_name: item.name.clone(),
260 data: TypeErrorData::SyntaxError(SyntaxError::new(alloc::string::String::from(
261 pe.what(),
262 ))),
263 });
264 }
265 unsafe {
266 let mut combined = parse_errors;
268 combined.append(&mut (*module_ptr).errors);
269 (*module_ptr).errors = combined;
270 }
271
272 item.module = module;
273 }
274}