1use crate::functions::follow_type::follow_type_id;
2use crate::functions::get_mutable_table_type::get_mutable_table_type;
3use crate::functions::get_mutable_type::get_mutable_type_id;
4use crate::functions::get_table_type::get_table_type;
5use crate::functions::get_type_alt_j::get_type_id;
6use crate::functions::occurs_check_type_utils::occurs_check_type_id_type_id;
7use crate::functions::saturate_arguments::saturate_arguments;
8use crate::functions::shallow_clone_clone_alt_b::shallow_clone;
9use crate::records::clone_state::CloneState;
10use crate::records::constraint::Constraint;
11use crate::records::constraint_solver::ConstraintSolver;
12use crate::records::generic_type_visitor::GenericTypeVisitorTrait;
13use crate::records::infinite_type_finder::InfiniteTypeFinder;
14use crate::records::instantiation_queuer::InstantiationQueuer;
15use crate::records::instantiation_queuer_deprecated::InstantiationQueuerDeprecated;
16use crate::records::instantiation_signature::InstantiationSignature;
17use crate::records::iterative_type_visitor::IterativeTypeVisitorTrait;
18use crate::records::metatable_type::MetatableType;
19use crate::records::occurs_check_failed::OccursCheckFailed;
20use crate::records::pending_expansion_type::PendingExpansionType;
21use crate::records::reduce_constraint::ReduceConstraint;
22use crate::records::table_type::TableType;
23use crate::records::type_alias_expansion_constraint::TypeAliasExpansionConstraint;
24use crate::records::type_function_instance_type::TypeFunctionInstanceType;
25use crate::records::unknown_symbol::{Context, UnknownSymbol};
26use crate::type_aliases::constraint_v::ConstraintV;
27use crate::type_aliases::type_error_data::TypeErrorData;
28use luaur_ast::records::ast_name::AstName;
29use luaur_common::FFlag;
30
31impl ConstraintSolver {
32 pub fn try_dispatch_type_alias_expansion_constraint_not_null_constraint(
33 &mut self,
34 c: &TypeAliasExpansionConstraint,
35 constraint: *const Constraint,
36 ) -> bool {
37 let petv = unsafe { get_type_id::<PendingExpansionType>(follow_type_id(c.target)) };
38 if petv.is_null() {
39 self.unblock_type_id_location(c.target, unsafe { (*constraint).location });
40 return true;
41 }
42
43 let petv = unsafe { &*petv };
44 let alias_name = ast_name_to_string(petv.name);
45 let alias_prefix = petv.prefix.map(ast_name_to_string);
46 let raw_type_arguments = petv.type_arguments.clone();
47 let raw_pack_arguments = petv.pack_arguments.clone();
48
49 let tf = unsafe {
50 if let Some(prefix) = &alias_prefix {
51 (*(*constraint).scope).lookup_imported_type(prefix, &alias_name)
52 } else {
53 (*(*constraint).scope).lookup_type(&alias_name)
54 }
55 };
56
57 let Some(tf) = tf else {
58 self.report_error_type_error_data_location(
59 TypeErrorData::UnknownSymbol(UnknownSymbol::new(alias_name, Context::Type)),
60 unsafe { &(*constraint).location },
61 );
62 bind_alias_expansion_result(self, c, constraint, unsafe {
63 (*self.builtin_types).errorType
64 });
65 return true;
66 };
67
68 if unsafe {
69 !get_type_id::<TypeFunctionInstanceType>(follow_type_id(tf.r#type())).is_null()
70 } {
71 self.push_constraint(
72 unsafe { core::ptr::NonNull::new_unchecked((*constraint).scope) },
73 unsafe { (*constraint).location },
74 ConstraintV::Reduce(ReduceConstraint { ty: tf.r#type() }),
75 );
76 }
77
78 let lhs = unsafe { follow_type_id(c.target) };
79 let rhs = tf.r#type();
80 if occurs_check_type_id_type_id(lhs, rhs) {
81 self.report_error_type_error_data_location(
82 TypeErrorData::OccursCheckFailed(OccursCheckFailed::default()),
83 unsafe { &(*constraint).location },
84 );
85 bind_alias_expansion_result(self, c, constraint, unsafe {
86 (*self.builtin_types).errorType
87 });
88 return true;
89 }
90
91 if tf.type_params().is_empty() && tf.type_pack_params().is_empty() {
92 bind_alias_expansion_result(self, c, constraint, tf.r#type());
93 return true;
94 }
95
96 let (type_arguments, pack_arguments) = unsafe {
97 saturate_arguments(
98 &mut *self.arena,
99 &mut *self.builtin_types,
100 &tf,
101 &raw_type_arguments,
102 &raw_pack_arguments,
103 )
104 };
105
106 let same_types = type_arguments.len() == tf.type_params().len()
107 && type_arguments
108 .iter()
109 .zip(tf.type_params())
110 .all(|(arg, param)| *arg == param.ty);
111 let same_packs = pack_arguments.len() == tf.type_pack_params().len()
112 && pack_arguments
113 .iter()
114 .zip(tf.type_pack_params())
115 .all(|(arg, param)| *arg == param.tp);
116
117 if same_types && same_packs {
118 bind_alias_expansion_result(self, c, constraint, tf.r#type());
119 return true;
120 }
121
122 let signature = InstantiationSignature {
123 fn_sig: tf.clone(),
124 arguments: type_arguments.clone(),
125 pack_arguments: pack_arguments.clone(),
126 };
127
128 if let Some(cached) = self.instantiated_aliases.find(&signature).copied() {
129 bind_alias_expansion_result(self, c, constraint, cached);
130 return true;
131 }
132
133 let mut itf = InfiniteTypeFinder::infinite_type_finder_infinite_type_finder(
134 self,
135 &signature,
136 unsafe { core::ptr::NonNull::new_unchecked((*constraint).scope) },
137 );
138 itf.run_type_id(tf.r#type());
139
140 if itf.found_infinite_type {
141 bind_alias_expansion_result(self, c, constraint, unsafe {
142 (*self.builtin_types).errorType
143 });
144 unsafe {
145 (*(*constraint).scope)
146 .invalid_type_aliases
147 .try_insert(alias_name.clone(), (*constraint).location);
148 }
149 return true;
150 }
151
152 let mut apply_type_function =
153 crate::records::apply_type_function::ApplyTypeFunction::apply_type_function(self.arena);
154 for (i, ty) in type_arguments.iter().enumerate() {
155 *apply_type_function
156 .type_arguments
157 .get_or_insert(tf.type_params()[i].ty) = *ty;
158 }
159
160 for (i, tp) in pack_arguments.iter().enumerate() {
161 *apply_type_function
162 .type_pack_arguments
163 .get_or_insert(tf.type_pack_params()[i].tp) = *tp;
164 }
165
166 let Some(mut instantiated) = apply_type_function.substitute_type_id(tf.r#type()) else {
167 bind_alias_expansion_result(self, c, constraint, unsafe {
168 (*self.builtin_types).errorType
169 });
170 return true;
171 };
172
173 let mut target = unsafe { follow_type_id(instantiated) };
174
175 if FFlag::LuauIterativeInstantiationQueuer.get() {
176 let mut queuer = InstantiationQueuer::instantiation_queuer(
177 unsafe { core::ptr::NonNull::new_unchecked((*constraint).scope) },
178 unsafe { &(*constraint).location },
179 self as *mut ConstraintSolver,
180 );
181 queuer.run_type_id(target);
182 } else {
183 let mut queuer = InstantiationQueuerDeprecated::instantiation_queuer_deprecated_instantiation_queuer_deprecated(
184 unsafe { core::ptr::NonNull::new_unchecked((*constraint).scope) },
185 unsafe { &(*constraint).location },
186 self as *mut ConstraintSolver,
187 );
188 queuer.traverse_type_id(target);
189 }
190
191 if unsafe { (*target).persistent || (*target).owning_arena != self.arena } {
192 bind_alias_expansion_result(self, c, constraint, target);
193 return true;
194 }
195
196 let tf_table = get_table_type(tf.r#type())
197 .map(|table| table as *const TableType)
198 .unwrap_or(core::ptr::null());
199 let target_table = get_table_type(target)
200 .map(|table| table as *const TableType)
201 .unwrap_or(core::ptr::null());
202 let needs_clone = unsafe { follow_type_id(tf.r#type()) == target }
203 || (!tf_table.is_null() && tf_table == target_table)
204 || type_arguments.iter().any(|other| *other == target);
205
206 let mut table = get_mutable_table_type(target);
207 if !table.is_null() {
208 if needs_clone {
209 if unsafe { !get_type_id::<MetatableType>(target).is_null() } {
210 let mut clone_state = unsafe { CloneState::new(&mut *self.builtin_types) };
211 instantiated =
212 unsafe { shallow_clone(target, &mut *self.arena, &mut clone_state, true) };
213 let metatable = unsafe { get_mutable_type_id::<MetatableType>(instantiated) };
214 unsafe {
215 (*metatable).table = shallow_clone(
216 (*metatable).table(),
217 &mut *self.arena,
218 &mut clone_state,
219 true,
220 );
221 table = get_mutable_type_id::<TableType>((*metatable).table());
222 }
223 } else if unsafe { !get_type_id::<TableType>(target).is_null() } {
224 let mut clone_state = unsafe { CloneState::new(&mut *self.builtin_types) };
225 instantiated =
226 unsafe { shallow_clone(target, &mut *self.arena, &mut clone_state, true) };
227 table = unsafe { get_mutable_type_id::<TableType>(instantiated) };
228 }
229
230 target = unsafe { follow_type_id(instantiated) };
231 }
232
233 unsafe {
234 (*table).instantiated_type_params = type_arguments.clone();
235 (*table).instantiated_type_pack_params = pack_arguments.clone();
236 (*table).definition_location = (*constraint).location;
237 if let Some(module) = &self.module {
238 (*table).definition_module_name = module.name.clone();
239 }
240 }
241 }
242
243 bind_alias_expansion_result(self, c, constraint, target);
244 self.instantiated_aliases.try_insert(signature, target);
245
246 true
247 }
248}
249
250fn bind_alias_expansion_result(
251 solver: &mut ConstraintSolver,
252 c: &TypeAliasExpansionConstraint,
253 constraint: *const Constraint,
254 result: crate::type_aliases::type_id::TypeId,
255) {
256 let c_target = unsafe { follow_type_id(c.target) };
257
258 if occurs_check_type_id_type_id(c_target, result) {
259 solver.report_error_type_error_data_location(
260 TypeErrorData::OccursCheckFailed(OccursCheckFailed::default()),
261 unsafe { &(*constraint).location },
262 );
263 solver.bind_not_null_constraint_type_id_type_id(constraint, c_target, unsafe {
264 (*solver.builtin_types).errorType
265 });
266 } else {
267 solver.bind_not_null_constraint_type_id_type_id(constraint, c_target, result);
268 }
269}
270
271fn ast_name_to_string(name: AstName) -> String {
272 if name.value.is_null() {
273 String::new()
274 } else {
275 unsafe { core::ffi::CStr::from_ptr(name.value) }
276 .to_string_lossy()
277 .into_owned()
278 }
279}