Skip to main content

luaur_analysis/methods/
constraint_solver_try_dispatch_constraint_solver_alt_o.rs

1use crate::enums::polarity::Polarity;
2use crate::functions::as_mutable_type::as_mutable_type_id;
3use crate::functions::extend_type_pack::extend_type_pack;
4use crate::functions::follow_type::follow_type_id;
5use crate::functions::follow_type_pack::follow_type_pack_id;
6use crate::functions::fresh_type::fresh_type;
7use crate::functions::get_type_alt_j::get_type_id;
8use crate::functions::track_interior_free_type::track_interior_free_type;
9use crate::records::blocked_type::BlockedType;
10use crate::records::constraint::Constraint;
11use crate::records::constraint_solver::ConstraintSolver;
12use crate::records::pending_expansion_type::PendingExpansionType;
13use crate::records::unpack_constraint::UnpackConstraint;
14use crate::type_aliases::type_id::TypeId;
15use crate::type_aliases::type_variant::TypeVariant;
16use luaur_common::macros::luau_assert::LUAU_ASSERT;
17use luaur_common::FFlag;
18
19impl ConstraintSolver {
20    pub fn try_dispatch_unpack_constraint_not_null_constraint(
21        &mut self,
22        c: &UnpackConstraint,
23        constraint: *const Constraint,
24    ) -> bool {
25        let source_pack = unsafe { follow_type_pack_id(c.source_pack) };
26
27        if self.is_blocked_type_pack_id(source_pack) {
28            return self.block_type_pack_id_not_null_constraint(source_pack, constraint);
29        }
30
31        let src_pack = unsafe {
32            extend_type_pack(
33                &mut *self.arena,
34                self.builtin_types,
35                source_pack,
36                c.result_pack.len(),
37                alloc::vec::Vec::new(),
38            )
39        };
40
41        let mut i = 0;
42        while i < c.result_pack.len() {
43            if i >= src_pack.head.len() {
44                break;
45            }
46
47            let src_ty = unsafe { follow_type_id(src_pack.head[i]) };
48            let result_ty = unsafe { follow_type_id(c.result_pack[i]) };
49
50            if unsafe { !get_type_id::<BlockedType>(result_ty).is_null() } {
51                LUAU_ASSERT!(can_mutate_type_id(result_ty, constraint));
52
53                if unsafe { follow_type_id(src_ty) } == result_ty {
54                    let fresh_ty = unsafe {
55                        fresh_type(
56                            &mut *self.arena,
57                            &*self.builtin_types,
58                            (*constraint).scope,
59                            Polarity::Positive,
60                        )
61                    };
62                    track_interior_free_type(unsafe { (*constraint).scope }, fresh_ty);
63
64                    if FFlag::LuauConstraintGraph.get() {
65                        self.bind_not_null_constraint_type_id_type_id(
66                            constraint, result_ty, fresh_ty,
67                        );
68                    } else {
69                        self.deprecate_d_shift_references(result_ty, fresh_ty);
70                        unsafe {
71                            (*as_mutable_type_id(result_ty)).ty = TypeVariant::Bound(fresh_ty);
72                        }
73                    }
74                } else {
75                    self.bind_not_null_constraint_type_id_type_id(constraint, result_ty, src_ty);
76                }
77            } else {
78                self.constraint_solver_unify(constraint, src_ty, result_ty);
79            }
80
81            if !FFlag::LuauConstraintGraph.get() {
82                self.unblock_type_id_location(result_ty, unsafe { (*constraint).location });
83            }
84
85            i += 1;
86        }
87
88        while i < c.result_pack.len() {
89            let result_ty = unsafe { follow_type_id(c.result_pack[i]) };
90            LUAU_ASSERT!(can_mutate_type_id(result_ty, constraint));
91
92            if unsafe {
93                !get_type_id::<BlockedType>(result_ty).is_null()
94                    || !get_type_id::<PendingExpansionType>(result_ty).is_null()
95            } {
96                self.bind_not_null_constraint_type_id_type_id(constraint, result_ty, unsafe {
97                    (*self.builtin_types).nilType
98                });
99            }
100
101            i += 1;
102        }
103
104        true
105    }
106}
107
108fn can_mutate_type_id(ty: TypeId, constraint: *const Constraint) -> bool {
109    let blocked = unsafe { get_type_id::<BlockedType>(ty) };
110    if !blocked.is_null() {
111        let owner = unsafe { (*blocked).getOwner() };
112        LUAU_ASSERT!(!owner.is_null());
113        return owner == constraint;
114    }
115
116    true
117}