Skip to main content

luaur_analysis/methods/
constraint_solver_try_dispatch_constraint_solver_alt_h.rs

1use crate::enums::polarity::Polarity;
2use crate::enums::unify_result::UnifyResult;
3use crate::functions::find_unique_types_ast_utils_alt_d::find_unique_types;
4use crate::functions::flatten_type_pack::flatten_type_pack_id;
5use crate::functions::follow_type::follow_type_id;
6use crate::functions::follow_type_pack::follow_type_pack_id;
7use crate::functions::get_approximate_return_type_for_function_call_type_utils_alt_b::get_approximate_return_type_for_function_call_type_id;
8use crate::functions::get_mutable_type::get_mutable_type_id;
9use crate::functions::get_type_alt_j::get_type_id;
10use crate::functions::instantiate_2_instantiation_2::instantiate_2 as instantiate_2_type_id;
11use crate::functions::instantiate_2_instantiation_2_alt_b::instantiate_2;
12use crate::functions::shallow_clone_clone_alt_b::shallow_clone;
13use crate::functions::track_interior_free_type::track_interior_free_type;
14use crate::functions::track_interior_free_type_pack::track_interior_free_type_pack;
15use crate::records::any_type::AnyType;
16use crate::records::builtin_types::BuiltinTypes;
17use crate::records::clone_state::CloneState;
18use crate::records::constraint::Constraint;
19use crate::records::constraint_solver::ConstraintSolver;
20use crate::records::free_type::FreeType;
21use crate::records::function_call_constraint::FunctionCallConstraint;
22use crate::records::function_type::FunctionType;
23use crate::records::generic_type_visitor::GenericTypeVisitorTrait;
24use crate::records::instantiation_queuer::InstantiationQueuer;
25use crate::records::instantiation_queuer_deprecated::InstantiationQueuerDeprecated;
26use crate::records::internal_error_reporter::InternalErrorReporter;
27use crate::records::intersection_type::IntersectionType;
28use crate::records::iterative_type_visitor::IterativeTypeVisitorTrait;
29use crate::records::magic_function_call_context::MagicFunctionCallContext;
30use crate::records::magic_refinement_context::MagicRefinementContext;
31use crate::records::never_type::NeverType;
32use crate::records::occurs_check_failed::OccursCheckFailed;
33use crate::records::overload_resolver::OverloadResolver;
34use crate::records::subtyping::Subtyping;
35use crate::records::unification_too_complex::UnificationTooComplex;
36use crate::records::unifier_2::Unifier2;
37use crate::records::union_type::UnionType;
38use crate::records::unknown_type::UnknownType;
39use crate::type_aliases::error_type::ErrorType;
40use crate::type_aliases::type_id::TypeId;
41use core::ptr::NonNull;
42use luaur_ast::records::ast_node::AstNode;
43use luaur_common::records::dense_hash_map::DenseHashMap;
44use luaur_common::records::dense_hash_set::DenseHashSet;
45use luaur_common::FFlag;
46
47impl ConstraintSolver {
48    pub fn try_dispatch_function_call_constraint_not_null_constraint_bool(
49        &mut self,
50        c: &FunctionCallConstraint,
51        constraint: *const Constraint,
52        _force: bool,
53    ) -> bool {
54        let mut fn_ty = unsafe { follow_type_id(c.fn_type) };
55        let args_pack = unsafe { follow_type_pack_id(c.args_pack) };
56        let result = unsafe { follow_type_pack_id(c.result) };
57
58        if self.is_blocked_type_id(fn_ty) {
59            return self.block_type_id_not_null_constraint(c.fn_type, constraint);
60        }
61
62        if unsafe { !get_type_id::<AnyType>(fn_ty).is_null() } {
63            self.bind_not_null_constraint_type_pack_id_type_pack_id(constraint, c.result, unsafe {
64                (*self.builtin_types).anyTypePack
65            });
66            self.fill_in_discriminant_types(constraint, &c.discriminant_types);
67            return true;
68        }
69
70        if unsafe { !get_type_id::<ErrorType>(fn_ty).is_null() } {
71            self.bind_not_null_constraint_type_pack_id_type_pack_id(constraint, c.result, unsafe {
72                (*self.builtin_types).errorTypePack
73            });
74            self.fill_in_discriminant_types(constraint, &c.discriminant_types);
75            return true;
76        }
77
78        if unsafe { !get_type_id::<NeverType>(fn_ty).is_null() } {
79            self.bind_not_null_constraint_type_pack_id_type_pack_id(constraint, c.result, unsafe {
80                (*self.builtin_types).neverTypePack
81            });
82            self.fill_in_discriminant_types(constraint, &c.discriminant_types);
83            return true;
84        }
85
86        let (args_head, args_tail) = flatten_type_pack_id(args_pack);
87        let mut blocked = false;
88
89        for arg in args_head {
90            if self.is_blocked_type_id(arg) {
91                self.block_type_id_not_null_constraint(arg, constraint);
92                blocked = true;
93            }
94        }
95
96        if let Some(tail) = args_tail {
97            if self.is_blocked_type_pack_id(tail) {
98                self.block_type_pack_id_not_null_constraint(tail, constraint);
99                blocked = true;
100            }
101        }
102
103        if blocked {
104            return false;
105        }
106
107        let scope = unsafe { (*constraint).scope };
108        let location = unsafe { (*constraint).location };
109
110        let mut args_pack = args_pack;
111
112        fn collapse(parts: &[TypeId]) -> Option<TypeId> {
113            let first = parts.first().copied()?;
114            let first = unsafe { follow_type_id(first) };
115
116            for part in parts {
117                if unsafe { follow_type_id(*part) } != first {
118                    return None;
119                }
120            }
121
122            Some(first)
123        }
124
125        if let Some(utv) = unsafe { get_type_id::<UnionType>(fn_ty).as_ref() } {
126            fn_ty = collapse(&utv.options).unwrap_or(fn_ty);
127        } else if let Some(itv) = unsafe { get_type_id::<IntersectionType>(fn_ty).as_ref() } {
128            fn_ty = collapse(&itv.parts).unwrap_or(fn_ty);
129        }
130
131        let mut used_magic = false;
132        if let Some(ftv) = unsafe { get_type_id::<FunctionType>(fn_ty).as_ref() } {
133            if let Some(magic) = &ftv.magic {
134                if !c.call_site.is_null() {
135                    used_magic = (magic.infer)(&MagicFunctionCallContext {
136                        solver: NonNull::new(self as *mut ConstraintSolver).unwrap(),
137                        constraint: NonNull::new(constraint as *mut Constraint).unwrap(),
138                        call_site: NonNull::new(c.call_site).unwrap(),
139                        arguments: c.args_pack,
140                        result,
141                    });
142                    (magic.refine)(&MagicRefinementContext {
143                        scope,
144                        call_site: c.call_site,
145                        discriminant_types: c.discriminant_types.clone(),
146                    });
147                }
148            }
149        }
150
151        if luaur_common::FFlag::LuauExplicitTypeInstantiationSupport.get()
152            && (!c.type_arguments.is_empty() || !c.type_pack_arguments.is_empty())
153        {
154            fn_ty = self.instantiate_function_type(
155                c.fn_type,
156                &c.type_arguments,
157                &c.type_pack_arguments,
158                scope,
159                &location,
160            );
161        }
162
163        self.fill_in_discriminant_types(constraint, &c.discriminant_types);
164
165        let mut overload_to_use = fn_ty;
166
167        if unsafe { get_type_id::<FunctionType>(overload_to_use).is_null() } {
168            let mut resolver = OverloadResolver::new(
169                self.builtin_types,
170                self.arena,
171                self.normalizer,
172                self.type_function_runtime,
173                scope,
174                &mut self.ice_reporter as *mut InternalErrorReporter,
175                &mut self.limits as *mut _,
176                location,
177            );
178
179            let mut unique_types: DenseHashSet<TypeId> = DenseHashSet::new(core::ptr::null_mut());
180            if !c.call_site.is_null() {
181                if let Some(module) = &self.module {
182                    let module_ptr = alloc::sync::Arc::as_ptr(module);
183                    unsafe {
184                        find_unique_types(
185                            &mut unique_types as *mut DenseHashSet<TypeId>,
186                            (*c.call_site).args.as_slice(),
187                            &(*module_ptr).ast_types as *const _,
188                        );
189                    }
190                }
191            }
192
193            let resolution = resolver.resolve_overload(
194                overload_to_use,
195                args_pack,
196                if c.call_site.is_null() {
197                    luaur_ast::records::location::Location::default()
198                } else {
199                    unsafe { (*(*c.call_site).func).base.location }
200                },
201                &mut unique_types as *mut DenseHashSet<TypeId>,
202                true,
203            );
204
205            let selected = resolution.get_unambiguous_overload();
206            if let Some(overload) = selected.overload {
207                overload_to_use = overload;
208            } else {
209                self.bind_not_null_constraint_type_pack_id_type_pack_id(
210                    constraint,
211                    c.result,
212                    unsafe { (*self.builtin_types).errorTypePack },
213                );
214                return true;
215            }
216
217            if resolution.metamethods.contains(&overload_to_use) {
218                args_pack = unsafe {
219                    (*self.arena).add_type_pack_vector_type_id_optional_type_pack_id(
220                        alloc::vec![fn_ty],
221                        Some(args_pack),
222                    )
223                };
224            }
225        }
226
227        let ret_tp = unsafe { (*self.arena).fresh_type_pack(scope, Polarity::Positive) };
228        track_interior_free_type_pack(scope, ret_tp);
229
230        let inferred_ty = unsafe {
231            (*self.arena).add_type(FunctionType::function_type_new(
232                args_pack, ret_tp, None, false,
233            ))
234        };
235
236        let mut u2 = Unifier2::unifier_2_not_null_type_arena_not_null_builtin_types_not_null_scope_not_null_internal_error_reporter(
237            NonNull::new(self.arena).unwrap(),
238            NonNull::new(self.builtin_types).unwrap(),
239            NonNull::new(scope).unwrap(),
240            NonNull::new(&self.ice_reporter as *const InternalErrorReporter as *mut InternalErrorReporter).unwrap(),
241        );
242
243        let unify_result = u2.unify(overload_to_use, inferred_ty);
244
245        for free_ty in u2.new_fresh_types.iter().copied() {
246            track_interior_free_type(scope, free_ty);
247        }
248        for free_tp in u2.new_fresh_type_packs.iter().copied() {
249            track_interior_free_type_pack(scope, free_tp);
250        }
251
252        let mut result_tp = ret_tp;
253        if !u2.generic_substitutions.empty() || !u2.generic_pack_substitutions.empty() {
254            let mut subtyping = Subtyping::subtyping_owned(
255                self.builtin_types,
256                self.arena,
257                self.normalizer,
258                self.type_function_runtime,
259                &self.ice_reporter as *const InternalErrorReporter as *mut InternalErrorReporter,
260            );
261
262            let mut has_bound = false;
263            for (_, ty) in u2.generic_substitutions.iter() {
264                if let Some(ftv) = unsafe { get_type_id::<FreeType>(*ty).as_ref() } {
265                    let lower_bound = unsafe { follow_type_id(ftv.lower_bound) };
266                    let upper_bound = unsafe { follow_type_id(ftv.upper_bound) };
267                    has_bound = unsafe { get_type_id::<NeverType>(lower_bound).is_null() }
268                        || unsafe { get_type_id::<UnknownType>(upper_bound).is_null() };
269
270                    if has_bound {
271                        break;
272                    }
273                }
274            }
275
276            if unsafe { !get_type_id::<FunctionType>(overload_to_use).is_null() } && has_bound {
277                let mut clone_state = CloneState {
278                    builtin_types: self.builtin_types,
279                    seen_types: DenseHashMap::new(core::ptr::null()),
280                    seen_type_packs: DenseHashMap::new(core::ptr::null()),
281                };
282
283                let cloned_ty = shallow_clone(
284                    overload_to_use,
285                    unsafe { &mut *self.arena },
286                    &mut clone_state,
287                    true,
288                );
289                let cloned_fn = unsafe { get_mutable_type_id::<FunctionType>(cloned_ty) };
290                unsafe {
291                    (*cloned_fn).generics.clear();
292                    (*cloned_fn).generic_packs.clear();
293                }
294
295                if let Some(subst) = instantiate_2_type_id(
296                    self.arena,
297                    u2.generic_substitutions.clone(),
298                    u2.generic_pack_substitutions.clone(),
299                    &mut subtyping as *mut Subtyping,
300                    scope,
301                    cloned_ty,
302                ) {
303                    overload_to_use = unsafe { follow_type_id(subst) };
304
305                    if let Some(instantiated_fn) =
306                        unsafe { get_type_id::<FunctionType>(overload_to_use).as_ref() }
307                    {
308                        result_tp = unsafe { follow_type_pack_id(instantiated_fn.ret_types) };
309                    } else {
310                        self.report_error_type_error_data_location(
311                            crate::records::code_too_complex::CodeTooComplex::default().into(),
312                            &location,
313                        );
314                        result_tp = unsafe { (*self.builtin_types).errorTypePack };
315                    }
316                } else {
317                    self.report_error_type_error_data_location(
318                        crate::records::code_too_complex::CodeTooComplex::default().into(),
319                        &location,
320                    );
321                    result_tp = unsafe { (*self.builtin_types).errorTypePack };
322                }
323            } else {
324                let approximate_ret =
325                    get_approximate_return_type_for_function_call_type_id(overload_to_use)
326                        .unwrap_or(unsafe { (*self.builtin_types).errorTypePack });
327
328                if let Some(subst) = instantiate_2(
329                    self.arena,
330                    u2.generic_substitutions.clone(),
331                    u2.generic_pack_substitutions.clone(),
332                    &mut subtyping as *mut Subtyping,
333                    scope,
334                    approximate_ret,
335                ) {
336                    result_tp = subst;
337                } else {
338                    self.report_error_type_error_data_location(
339                        crate::records::code_too_complex::CodeTooComplex::default().into(),
340                        &location,
341                    );
342                    result_tp = unsafe { (*self.builtin_types).errorTypePack };
343                }
344            }
345        }
346
347        if !used_magic {
348            self.bind_not_null_constraint_type_pack_id_type_pack_id(
349                constraint, c.result, result_tp,
350            );
351        }
352
353        for (expanded, additions) in u2.expanded_free_types.iter() {
354            for addition in additions {
355                self.upper_bound_contributors
356                    .get_or_insert(*expanded)
357                    .push((location, *addition));
358            }
359        }
360
361        match unify_result {
362            UnifyResult::Ok => {
363                if !c.call_site.is_null() && !c.ast_overload_resolved_types.is_null() {
364                    unsafe {
365                        *(*c.ast_overload_resolved_types)
366                            .get_or_insert(c.call_site as *const AstNode) = if used_magic {
367                            inferred_ty
368                        } else {
369                            overload_to_use
370                        };
371                    }
372                }
373            }
374            UnifyResult::TooComplex => self.report_error_type_error_data_location(
375                UnificationTooComplex::default().into(),
376                &location,
377            ),
378            UnifyResult::OccursCheckFailed => self.report_error_type_error_data_location(
379                OccursCheckFailed::default().into(),
380                &location,
381            ),
382        }
383
384        if FFlag::LuauIterativeInstantiationQueuer.get() {
385            let mut queuer = InstantiationQueuer::instantiation_queuer(
386                NonNull::new(scope).unwrap(),
387                &location,
388                self as *mut ConstraintSolver,
389            );
390            queuer.run_type_id(overload_to_use);
391            if FFlag::LuauAlsoInstantiateInferredArguments.get() {
392                queuer.run_type_pack_id(args_pack);
393            }
394            queuer.run_type_pack_id(result);
395        } else {
396            let mut queuer = InstantiationQueuerDeprecated::instantiation_queuer_deprecated_instantiation_queuer_deprecated(
397                NonNull::new(scope).unwrap(),
398                &location,
399                self as *mut ConstraintSolver,
400            );
401            queuer.traverse_type_id(overload_to_use);
402            if FFlag::LuauAlsoInstantiateInferredArguments.get() {
403                queuer.traverse_type_pack_id(args_pack);
404            }
405            queuer.traverse_type_pack_id(result);
406        }
407
408        if !FFlag::LuauConstraintGraph.get() {
409            self.unblock_type_pack_id_location(c.result, location);
410        }
411
412        true
413    }
414}