Skip to main content

luaur_analysis/methods/
constraint_generator_visit_constraint_generator.rs

1use crate::enums::control_flow::ControlFlow;
2use crate::functions::does_call_error::does_call_error;
3use crate::records::constraint_generator::ConstraintGenerator;
4use crate::records::recursion_counter::RecursionCounter;
5use crate::records::recursion_limiter::RecursionLimiter;
6use crate::records::scope::Scope;
7use crate::type_aliases::scope_ptr_constraint_generator::ScopePtr;
8use alloc::vec::Vec;
9use luaur_ast::records::ast_expr_call::AstExprCall;
10use luaur_ast::records::ast_node::AstNode;
11use luaur_ast::records::ast_stat::AstStat;
12use luaur_ast::records::ast_stat_assign::AstStatAssign;
13use luaur_ast::records::ast_stat_block::AstStatBlock;
14use luaur_ast::records::ast_stat_break::AstStatBreak;
15use luaur_ast::records::ast_stat_class::AstStatClass;
16use luaur_ast::records::ast_stat_compound_assign::AstStatCompoundAssign;
17use luaur_ast::records::ast_stat_continue::AstStatContinue;
18use luaur_ast::records::ast_stat_declare_extern_type::AstStatDeclareExternType;
19use luaur_ast::records::ast_stat_declare_function::AstStatDeclareFunction;
20use luaur_ast::records::ast_stat_declare_global::AstStatDeclareGlobal;
21use luaur_ast::records::ast_stat_error::AstStatError;
22use luaur_ast::records::ast_stat_expr::AstStatExpr;
23use luaur_ast::records::ast_stat_for::AstStatFor;
24use luaur_ast::records::ast_stat_for_in::AstStatForIn;
25use luaur_ast::records::ast_stat_function::AstStatFunction;
26use luaur_ast::records::ast_stat_if::AstStatIf;
27use luaur_ast::records::ast_stat_local::AstStatLocal;
28use luaur_ast::records::ast_stat_local_function::AstStatLocalFunction;
29use luaur_ast::records::ast_stat_repeat::AstStatRepeat;
30use luaur_ast::records::ast_stat_return::AstStatReturn;
31use luaur_ast::records::ast_stat_type_alias::AstStatTypeAlias;
32use luaur_ast::records::ast_stat_type_function::AstStatTypeFunction;
33use luaur_ast::records::ast_stat_while::AstStatWhile;
34use luaur_ast::rtti::ast_node_as;
35use luaur_common::DFInt;
36use luaur_common::FFlag;
37use luaur_common::LUAU_ASSERT;
38
39impl ConstraintGenerator {
40    pub fn visit_scope_ptr_ast_stat(
41        &mut self,
42        scope: &ScopePtr,
43        stat: *mut AstStat,
44    ) -> ControlFlow {
45        unsafe {
46            let mut counter = RecursionCounter::recursion_counter_i32(&mut self.recursion_count);
47            let mut limiter: Option<RecursionLimiter> = None;
48
49            if self.recursion_count >= DFInt::LuauConstraintGeneratorRecursionLimit.get() as i32 {
50                self.report_code_too_complex((*stat).base.location);
51                return ControlFlow::None;
52            }
53
54            // C++ takes `const ScopePtr&`; sibling visit methods diverge between
55            // `*mut Scope` and `&ScopePtr` callee signatures, so adapt per callee.
56            let scope_raw: *mut Scope = scope.as_ref() as *const Scope as *mut Scope;
57
58            let node = stat as *mut AstNode;
59            if (*node).is::<AstStatBlock>() {
60                self.visit_scope_ptr_ast_stat_block(scope, stat as *mut AstStatBlock)
61            } else if (*node).is::<AstStatIf>() {
62                self.visit_scope_ptr_ast_stat_if(scope, stat as *mut AstStatIf)
63            } else if (*node).is::<AstStatWhile>() {
64                self.visit_scope_ptr_ast_stat_while(scope, stat as *mut AstStatWhile)
65            } else if (*node).is::<AstStatRepeat>() {
66                self.visit_scope_ptr_ast_stat_repeat(scope, stat as *mut AstStatRepeat)
67            } else if (*node).is::<AstStatBreak>() {
68                ControlFlow::Breaks
69            } else if (*node).is::<AstStatContinue>() {
70                ControlFlow::Continues
71            } else if (*node).is::<AstStatReturn>() {
72                self.visit_scope_ptr_ast_stat_return(scope.clone(), stat as *mut AstStatReturn)
73            } else if (*node).is::<AstStatExpr>() {
74                let expr_stat = stat as *mut AstStatExpr;
75                self.check_pack_scope_ptr_ast_expr_vector_optional_type_id_bool(
76                    scope,
77                    (*expr_stat).expr,
78                    &Vec::new(),
79                    true,
80                );
81                let call = ast_node_as::<AstExprCall>((*expr_stat).expr as *mut AstNode);
82                if !call.is_null() && does_call_error(&*call) {
83                    return ControlFlow::Throws;
84                }
85                ControlFlow::None
86            } else if (*node).is::<AstStatLocal>() {
87                self.visit_scope_ptr_ast_stat_local(scope, stat as *mut AstStatLocal)
88            } else if (*node).is::<AstStatFor>() {
89                self.visit_scope_ptr_ast_stat_for(scope, stat as *mut AstStatFor)
90            } else if (*node).is::<AstStatForIn>() {
91                self.visit_scope_ptr_ast_stat_for_in(scope, stat as *mut AstStatForIn)
92            } else if (*node).is::<AstStatAssign>() {
93                self.visit_scope_ptr_ast_stat_assign(scope, stat as *mut AstStatAssign)
94            } else if (*node).is::<AstStatCompoundAssign>() {
95                self.visit_scope_ptr_ast_stat_compound_assign(
96                    scope,
97                    stat as *mut AstStatCompoundAssign,
98                )
99            } else if (*node).is::<AstStatFunction>() {
100                self.visit_scope_ptr_ast_stat_function(scope, stat as *mut AstStatFunction)
101            } else if (*node).is::<AstStatLocalFunction>() {
102                self.visit_scope_ptr_ast_stat_local_function(
103                    scope,
104                    stat as *mut AstStatLocalFunction,
105                )
106            } else if (*node).is::<AstStatTypeAlias>() {
107                self.visit_scope_ptr_ast_stat_type_alias(scope, stat as *mut AstStatTypeAlias)
108            } else if (*node).is::<AstStatTypeFunction>() {
109                self.visit_scope_ptr_ast_stat_type_function(scope, stat as *mut AstStatTypeFunction)
110            } else if (*node).is::<AstStatDeclareGlobal>() {
111                self.visit_scope_ptr_ast_stat_declare_global(
112                    scope_raw,
113                    stat as *mut AstStatDeclareGlobal,
114                )
115            } else if (*node).is::<AstStatDeclareFunction>() {
116                self.visit_scope_ptr_ast_stat_declare_function(
117                    scope,
118                    stat as *mut AstStatDeclareFunction,
119                )
120            } else if (*node).is::<AstStatDeclareExternType>() {
121                self.visit_scope_ptr_ast_stat_declare_extern_type(
122                    scope_raw,
123                    stat as *mut AstStatDeclareExternType,
124                )
125            } else if (*node).is::<AstStatClass>() {
126                LUAU_ASSERT!(FFlag::DebugLuauUserDefinedClasses.get());
127                self.visit_scope_ptr_ast_stat_class(scope, stat as *mut AstStatClass)
128            } else if (*node).is::<AstStatError>() {
129                self.visit_scope_ptr_ast_stat_error(scope, stat as *mut AstStatError)
130            } else {
131                LUAU_ASSERT!(false, "Internal error: Unknown AstStat type");
132                ControlFlow::None
133            }
134        }
135    }
136}