Skip to main content

luaur_analysis/methods/
constraint_solver_bind_constraint_solver_alt_b.rs

1//! `void ConstraintSolver::bind(NotNull<const Constraint> constraint, TypePackId tp, TypePackId boundTo)`
2//! (`Analysis/src/ConstraintSolver.cpp:982-1001`, hand-ported faithfully).
3
4use crate::enums::occurs_check_result::OccursCheckResult;
5use crate::functions::as_mutable_type_pack::as_mutable_type_pack_id;
6use crate::functions::follow_type_pack::follow_type_pack_id;
7use crate::functions::get_type_pack::get_type_pack_id;
8use crate::functions::occurs_check_type_utils_alt_b::occurs_check_type_pack_id_type_pack_id;
9use crate::records::blocked_type_pack::BlockedTypePack;
10use crate::records::constraint::Constraint;
11use crate::records::constraint_solver::ConstraintSolver;
12use crate::records::free_type_pack::FreeTypePack;
13use crate::records::internal_error::InternalError;
14use crate::type_aliases::type_pack_id::TypePackId;
15use luaur_common::macros::luau_assert::LUAU_ASSERT;
16use luaur_common::FFlag;
17
18impl ConstraintSolver {
19    pub fn bind_not_null_constraint_type_pack_id_type_pack_id(
20        &mut self,
21        constraint: *const Constraint,
22        tp: TypePackId,
23        bound_to: TypePackId,
24    ) {
25        LUAU_ASSERT!(unsafe {
26            !get_type_pack_id::<BlockedTypePack>(tp).is_null()
27                || !get_type_pack_id::<FreeTypePack>(tp).is_null()
28        });
29        LUAU_ASSERT!(can_mutate_type_pack_id(tp, constraint));
30
31        let bound_to = unsafe { follow_type_pack_id(bound_to) };
32        LUAU_ASSERT!(tp != bound_to);
33
34        let location = unsafe { (*constraint).location };
35
36        if FFlag::LuauOccursCheckForAllBindings.get()
37            && occurs_check_type_pack_id_type_pack_id(tp, bound_to) == OccursCheckResult::Fail
38        {
39            self.report_error_type_error_data_location(
40                InternalError {
41                    message: alloc::string::String::from("Attempted to create a type pack cycle"),
42                }
43                .into(),
44                &location,
45            );
46            let mutable_tp = unsafe { as_mutable_type_pack_id(tp) };
47            let mut err_arg = unsafe { (*self.builtin_types).errorTypePack };
48            crate::methods::unifiable_bound_type_pack_id_emplace_type_pack_bound_type_pack::emplace_type_pack(
49                mutable_tp,
50                &mut err_arg,
51            );
52        } else {
53            let mutable_tp = unsafe { as_mutable_type_pack_id(tp) };
54            let mut bound_arg = bound_to;
55            crate::methods::unifiable_bound_type_pack_id_emplace_type_pack_bound_type_pack::emplace_type_pack(
56                mutable_tp,
57                &mut bound_arg,
58            );
59        }
60
61        self.unblock_type_pack_id_location(tp, location);
62    }
63}
64
65// C++ `[[maybe_unused]] static bool canMutate(TypePackId tp, NotNull<const Constraint> constraint)`
66// (`Analysis/src/ConstraintSolver.cpp:101-111`), used only in asserts.
67fn can_mutate_type_pack_id(tp: TypePackId, constraint: *const Constraint) -> bool {
68    let blocked = unsafe { get_type_pack_id::<BlockedTypePack>(tp) };
69    if !blocked.is_null() {
70        let owner = unsafe { (*blocked).owner };
71        LUAU_ASSERT!(!owner.is_null());
72        return owner as *const Constraint == constraint;
73    }
74    true
75}