luaur_analysis/methods/
constraint_solver_try_dispatch_constraint_solver_alt_m.rs1use crate::enums::table_state::TableState;
2use crate::enums::value_context::ValueContext;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_mutable_type::getMutable;
5use crate::functions::get_type_alt_j::get_type_id;
6use crate::functions::lookup_extern_type_prop::lookup_extern_type_prop;
7use crate::functions::maybe_string::maybe_string;
8use crate::records::assign_prop_constraint::AssignPropConstraint;
9use crate::records::blocked_type::BlockedType;
10use crate::records::constraint::Constraint;
11use crate::records::constraint_solver::ConstraintSolver;
12use crate::records::extern_type::ExternType;
13use crate::records::metatable_type::MetatableType;
14use crate::records::property_type::Property;
15use crate::records::table_type::TableType;
16use crate::records::union_type::UnionType;
17use luaur_common::macros::luau_assert::LUAU_ASSERT;
18use luaur_common::FFlag;
19
20impl ConstraintSolver {
21 pub fn try_dispatch_assign_prop_constraint_not_null_constraint(
22 &mut self,
23 c: &AssignPropConstraint,
24 constraint: *const Constraint,
25 ) -> bool {
26 let mut lhs_type = unsafe { follow_type_id(c.lhs_type) };
27 let rhs_type = unsafe { follow_type_id(c.rhs_type) };
28
29 if self.is_blocked_type_id(lhs_type) {
30 return self.block_type_id_not_null_constraint(lhs_type, constraint);
31 }
32
33 let lhs_extern_type = unsafe { get_type_id::<ExternType>(lhs_type) };
34 if !lhs_extern_type.is_null() {
35 let prop = unsafe { lookup_extern_type_prop(&*lhs_extern_type, &c.prop_name) };
36 if prop.is_null() {
37 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
38 (*self.builtin_types).anyType
39 });
40 return true;
41 }
42
43 if let Some(write_ty) = unsafe { (*prop).write_ty } {
44 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, write_ty);
45 self.constraint_solver_unify(constraint, rhs_type, write_ty);
46 } else {
47 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
48 (*self.builtin_types).anyType
49 });
50 }
51
52 return true;
53 }
54
55 let lookup = self
56 .lookup_table_prop_not_null_constraint_type_id_string_value_context_bool_bool(
57 constraint,
58 lhs_type,
59 &c.prop_name,
60 ValueContext::LValue,
61 false,
62 false,
63 );
64 if !lookup.blocked_types.is_empty() {
65 for blocked in lookup.blocked_types {
66 self.block_type_id_not_null_constraint(blocked, constraint);
67 }
68 return false;
69 }
70
71 if let Some(prop_ty) = lookup.prop_type {
72 let bound_prop_ty = if lookup.is_index {
73 unsafe {
74 (*self.arena).add_type(UnionType {
75 options: alloc::vec![prop_ty, (*self.builtin_types).nilType],
76 })
77 }
78 } else {
79 prop_ty
80 };
81
82 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, bound_prop_ty);
83 self.constraint_solver_unify(constraint, rhs_type, prop_ty);
84 return true;
85 }
86
87 let mut lhs_table = unsafe { getMutable::<TableType>(lhs_type) };
88 if lhs_table.is_null() {
89 let lhs_meta = unsafe { get_type_id::<MetatableType>(lhs_type) };
90 if !lhs_meta.is_null() {
91 lhs_type = unsafe { follow_type_id((*lhs_meta).table) };
92 lhs_table = unsafe { getMutable::<TableType>(lhs_type) };
93 }
94 }
95
96 if !lhs_table.is_null() {
97 let table = unsafe { &mut *lhs_table };
98
99 if let Some(prop) = table.props.get_mut(&c.prop_name) {
100 if let Some(write_ty) = prop.write_ty {
101 self.bind_not_null_constraint_type_id_type_id(
102 constraint,
103 c.prop_type,
104 write_ty,
105 );
106 self.constraint_solver_unify(constraint, rhs_type, write_ty);
107 return true;
108 }
109
110 if (table.state == TableState::Unsealed || table.state == TableState::Free)
111 && prop.read_ty.is_some()
112 {
113 prop.write_ty = prop.read_ty;
114 let write_ty = prop.write_ty.unwrap();
115 self.bind_not_null_constraint_type_id_type_id(
116 constraint,
117 c.prop_type,
118 write_ty,
119 );
120 self.constraint_solver_unify(constraint, rhs_type, write_ty);
121 return true;
122 }
123
124 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
125 (*self.builtin_types).errorType
126 });
127 return true;
128 }
129
130 if let Some(indexer) = &table.indexer {
131 if maybe_string(indexer.index_type) {
132 let prop_ty = indexer.index_result_type;
133 let union = unsafe {
134 (*self.arena).add_type(UnionType {
135 options: alloc::vec![prop_ty, (*self.builtin_types).nilType],
136 })
137 };
138 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, union);
139 self.constraint_solver_unify(constraint, rhs_type, prop_ty);
140 return true;
141 }
142 }
143
144 if table.state == TableState::Unsealed || table.state == TableState::Free {
145 if FFlag::LuauConstraintGraph.get() {
146 LUAU_ASSERT!(!self.cgraph.is_null());
147 unsafe { (*self.cgraph).copy_dependencies_of_type_id(lhs_type, rhs_type) };
148 } else {
149 self.deprecate_d_shift_references(lhs_type, rhs_type);
150 }
151
152 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, rhs_type);
153
154 let mut prop = Property::rw_type_id(rhs_type);
155 prop.location = c.prop_location;
156 table.props.insert(c.prop_name.clone(), prop);
157
158 if table.state == TableState::Unsealed && c.decrement_prop_count {
159 LUAU_ASSERT!(table.remaining_props > 0);
160 table.remaining_props -= 1;
161 self.unblock_type_id_location(lhs_type, unsafe { (*constraint).location });
162 }
163
164 return true;
165 }
166 }
167
168 let prop_type_is_blocked = unsafe { !get_type_id::<BlockedType>(c.prop_type).is_null() };
169 if prop_type_is_blocked {
170 self.bind_not_null_constraint_type_id_type_id(constraint, c.prop_type, unsafe {
171 (*self.builtin_types).errorType
172 });
173 }
174
175 true
176 }
177}