luaur_analysis/methods/
constraint_solver_bind_constraint_solver.rs1use crate::enums::polarity::Polarity;
5use crate::functions::as_mutable_type::as_mutable_type_id;
6use crate::functions::follow_type::follow_type_id;
7use crate::functions::fresh_type::fresh_type;
8use crate::functions::get_type_alt_j::get_type_id;
9use crate::functions::track_interior_free_type::track_interior_free_type;
10use crate::records::blocked_type::BlockedType;
11use crate::records::constraint::Constraint;
12use crate::records::constraint_solver::ConstraintSolver;
13use crate::records::free_type::FreeType;
14use crate::records::pending_expansion_type::PendingExpansionType;
15use crate::type_aliases::type_id::TypeId;
16use crate::type_aliases::type_variant::TypeVariant;
17use luaur_common::macros::luau_assert::LUAU_ASSERT;
18use luaur_common::FFlag;
19
20impl ConstraintSolver {
21 pub fn bind_not_null_constraint_type_id_type_id(
22 &mut self,
23 constraint: *const Constraint,
24 ty: TypeId,
25 bound_to: TypeId,
26 ) {
27 LUAU_ASSERT!(unsafe {
28 !get_type_id::<BlockedType>(ty).is_null()
29 || !get_type_id::<FreeType>(ty).is_null()
30 || !get_type_id::<PendingExpansionType>(ty).is_null()
31 });
32 LUAU_ASSERT!(can_mutate_type_id(ty, constraint));
33
34 let bound_to = unsafe { follow_type_id(bound_to) };
35 let scope = unsafe { (*constraint).scope };
36 let location = unsafe { (*constraint).location };
37
38 if FFlag::LuauOccursCheckForAllBindings.get() {
39 if unsafe { follow_type_id(ty) } == bound_to {
43 let fresh_ty = fresh_type(
44 unsafe { &mut *self.arena },
45 unsafe { &*self.builtin_types },
46 scope,
47 Polarity::Mixed,
48 );
49 let mutable_ty = unsafe { as_mutable_type_id(ty) };
50 let mut fresh_arg = fresh_ty;
51 crate::methods::unifiable_bound_type_id_emplace_type_bound_type::unifiable_bound_type_id_emplace_type_bound_type(
52 unsafe { &mut *mutable_ty },
53 &mut fresh_arg,
54 );
55 track_interior_free_type(scope, fresh_ty);
56 self.unblock_type_id_location(ty, location);
57 return;
58 }
59 } else if unsafe { !get_type_id::<BlockedType>(ty).is_null() } && ty == bound_to {
60 let free_ty = FreeType::free_type_scope_type_id_type_id_polarity(
63 scope,
64 unsafe { (*self.builtin_types).neverType },
65 unsafe { (*self.builtin_types).unknownType },
66 Polarity::Mixed,
67 );
68 let mutable_ty = unsafe { as_mutable_type_id(ty) };
69 unsafe {
70 (*mutable_ty).ty = TypeVariant::Free(free_ty);
71 }
72 self.unblock_type_id_location(ty, location);
73 track_interior_free_type(scope, ty);
74 return;
75 }
76
77 let mutable_ty = unsafe { as_mutable_type_id(ty) };
78 let mut bound_arg = bound_to;
79 crate::methods::unifiable_bound_type_id_emplace_type_bound_type::unifiable_bound_type_id_emplace_type_bound_type(
80 unsafe { &mut *mutable_ty },
81 &mut bound_arg,
82 );
83
84 if !FFlag::LuauConstraintGraph.get() {
85 self.deprecate_d_shift_references(ty, bound_to);
87 }
88
89 self.unblock_type_id_location(ty, location);
90 }
91}
92
93fn can_mutate_type_id(ty: TypeId, constraint: *const Constraint) -> bool {
96 let blocked = unsafe { get_type_id::<BlockedType>(ty) };
97 if !blocked.is_null() {
98 let owner = unsafe { (*blocked).getOwner() };
99 LUAU_ASSERT!(!owner.is_null());
100 return owner == constraint;
101 }
102 true
103}