Skip to main content

luaur_analysis/methods/
constraint_generator_visit_block_without_child_scope.rs

1// ConstraintGenerator::visitBlockWithoutChildScope (ConstraintGenerator.cpp:1276-1297).
2use crate::enums::control_flow::ControlFlow;
3use crate::records::constraint_generator::ConstraintGenerator;
4use crate::records::recursion_counter::RecursionCounter;
5use crate::records::scope::Scope;
6use crate::type_aliases::scope_ptr_constraint_generator::ScopePtr;
7use core::mem::ManuallyDrop;
8use luaur_ast::records::ast_stat_block::AstStatBlock;
9use luaur_common::DFInt;
10
11impl ConstraintGenerator {
12    pub fn visit_block_without_child_scope(
13        &mut self,
14        scope: *mut Scope,
15        block: *mut AstStatBlock,
16    ) -> ControlFlow {
17        let _counter = RecursionCounter::recursion_counter_i32(&mut self.recursion_count);
18
19        if self.recursion_count >= DFInt::LuauConstraintGeneratorRecursionLimit.get() as i32 {
20            self.report_code_too_complex(unsafe { (*block).base.base.location });
21            return ControlFlow::None;
22        }
23
24        self.prototype_type_definitions(scope, block);
25
26        // Borrow the caller-owned `Scope` as a `ScopePtr` without taking ownership
27        // (C++ passes `const ScopePtr&`); ManuallyDrop keeps the refcount intact.
28        let scope_ptr: ManuallyDrop<ScopePtr> =
29            ManuallyDrop::new(unsafe { alloc::sync::Arc::from_raw(scope as *const Scope) });
30
31        let mut first_control_flow: Option<ControlFlow> = None;
32        let body = unsafe { (*block).body };
33        for i in 0..body.size {
34            let stat = unsafe { *body.data.add(i) };
35            let cf = self.visit_scope_ptr_ast_stat(&scope_ptr, stat);
36            if cf != ControlFlow::None && first_control_flow.is_none() {
37                first_control_flow = Some(cf);
38            }
39        }
40
41        first_control_flow.unwrap_or(ControlFlow::None)
42    }
43}