1use crate::records::class_decl_record::ClassDeclRecord;
2use crate::records::constraint_generator::ConstraintGenerator;
3use crate::records::function_signature::FunctionSignature;
4use crate::records::scope::Scope;
5use crate::type_aliases::scope_ptr_constraint_generator::ScopePtr;
6use crate::type_aliases::type_id::TypeId;
7use crate::type_aliases::type_pack_id::TypePackId;
8use crate::type_aliases::type_pack_variant::TypePackVariant;
9use alloc::vec::Vec;
10use luaur_ast::records::ast_expr::AstExpr;
11use luaur_ast::records::ast_expr_function::AstExprFunction;
12use luaur_ast::records::location::Location;
13use luaur_common::macros::luau_assert::LUAU_ASSERT;
14use luaur_common::FFlag;
15
16impl ConstraintGenerator {
17 pub fn check_function_signature(
18 &mut self,
19 parent: &ScopePtr,
20 enclosing_class: *mut ClassDeclRecord,
21 fn_node: *mut AstExprFunction,
22 expected_type: Option<TypeId>,
23 original_name: Option<Location>,
24 ) -> FunctionSignature {
25 let fn_ref = unsafe { &*fn_node };
26 LUAU_ASSERT!(
27 FFlag::DebugLuauUserDefinedClasses.get() || enclosing_class.is_null(),
28 "check_function_signature: enclosing_class must be null when DebugLuauUserDefinedClasses is off"
29 );
30
31 let mut generic_types: Vec<TypeId> = Vec::new();
32 let mut generic_type_packs: Vec<TypePackId> = Vec::new();
33
34 let mut expected_type_opt = expected_type;
35 if let Some(et) = expected_type_opt {
36 expected_type_opt = Some(unsafe { crate::functions::follow_type::follow_type_id(et) });
37 }
38
39 let has_generics = fn_ref.generics.size > 0 || fn_ref.generic_packs.size > 0;
40
41 let signature_scope: ScopePtr =
42 self.child_scope(fn_node as *mut crate::records::ast_node::AstNode, parent);
43
44 let mut return_type: TypePackId =
47 self.fresh_type_pack(&signature_scope, crate::enums::polarity::Polarity::Positive);
48 unsafe {
49 (*(signature_scope.as_ref() as *const Scope as *mut Scope)).return_type = return_type;
50 }
51
52 let body_scope: ScopePtr = self.child_scope(
53 fn_ref.body as *mut crate::records::ast_node::AstNode,
54 &signature_scope,
55 );
56
57 if has_generics {
58 let generic_definitions = self.create_generics(
59 &signature_scope,
60 crate::records::ast_array::AstArray {
61 data: fn_ref.generics.data,
62 size: fn_ref.generics.size,
63 },
64 false,
72 true,
73 );
74 let generic_pack_definitions = self.create_generic_packs(
75 &signature_scope,
76 crate::records::ast_array::AstArray {
77 data: fn_ref.generic_packs.data,
78 size: fn_ref.generic_packs.size,
79 },
80 false,
85 true,
86 );
87
88 for (_name, g) in &generic_definitions {
89 generic_types.push(g.ty);
90 }
91
92 for (_name, g) in &generic_pack_definitions {
93 generic_type_packs.push(g.tp);
94 }
95
96 expected_type_opt = None;
97 }
98
99 let mut arg_types: Vec<TypeId> = Vec::new();
100 let mut arg_names: Vec<Option<crate::records::function_argument::FunctionArgument>> =
101 Vec::new();
102 let mut expected_arg_pack = crate::records::type_pack::TypePack {
103 head: Vec::new(),
104 tail: None,
105 };
106
107 let mut expected_function: *const crate::records::function_type::FunctionType =
108 if let Some(et) = expected_type_opt {
109 unsafe {
110 crate::functions::get_type_alt_j::get_type_id::<
111 crate::records::function_type::FunctionType,
112 >(et)
113 }
114 } else {
115 core::ptr::null()
116 };
117
118 if let Some(et) = expected_type_opt {
121 if crate::functions::is_optional::is_optional(et)
122 && unsafe {
123 crate::functions::get_type_alt_j::get_type_id::<crate::records::any_type::AnyType>(et).is_null()
124 }
125 {
126 if let Some(ut) = unsafe {
127 crate::functions::get_type_alt_j::get_type_id::<
128 crate::records::union_type::UnionType,
129 >(et)
130 .as_ref()
131 } {
132 for u in &ut.options {
133 let ft = unsafe {
134 crate::functions::get_type_alt_j::get_type_id::<
135 crate::records::function_type::FunctionType,
136 >(*u)
137 };
138 if !ft.is_null() && !crate::functions::is_nil::is_nil(*u) {
139 expected_function = ft;
140 break;
141 }
142 }
143 }
144 }
145 }
146
147 if !expected_function.is_null() {
148 let ef = unsafe { &*expected_function };
149 expected_arg_pack = crate::functions::extend_type_pack::extend_type_pack(
150 unsafe { &mut *self.arena },
151 self.builtin_types,
152 ef.arg_types,
153 fn_ref.args.size as usize,
154 Vec::new(),
155 );
156
157 generic_types = ef.generics.clone();
158 generic_type_packs = ef.generic_packs.clone();
159 }
160
161 let mut has_explicit_self = false;
162 let mut has_self = false;
163
164 if FFlag::DebugLuauUserDefinedClasses.get() {
165 if !enclosing_class.is_null() && fn_ref.args.size > 0 {
166 let first_arg = unsafe { &**fn_ref.args.data };
167 let arg_name =
168 unsafe { core::ffi::CStr::from_ptr(first_arg.name.value).to_string_lossy() };
169 has_explicit_self = arg_name == "self";
170 }
171 has_self = has_explicit_self || !fn_ref.self_.is_null();
172
173 if has_self {
174 let mut self_type: TypeId = core::ptr::null();
175 if !enclosing_class.is_null() {
176 self_type = unsafe { (*enclosing_class).ty };
177 } else {
178 self_type = self
179 .fresh_type(&signature_scope, crate::enums::polarity::Polarity::Negative);
180 }
181
182 let mut self_local: *mut luaur_ast::records::ast_local::AstLocal =
183 std::ptr::null_mut();
184 if !fn_ref.self_.is_null() {
185 self_local = fn_ref.self_;
186 } else if has_explicit_self {
187 self_local = unsafe { *fn_ref.args.data };
188 }
189
190 LUAU_ASSERT!(!self_local.is_null());
191
192 arg_types.push(self_type);
193 let arg_name = unsafe {
194 core::ffi::CStr::from_ptr((*self_local).name.value).to_string_lossy()
195 };
196 arg_names.push(Some(crate::records::function_argument::FunctionArgument {
197 name: arg_name.into_owned(),
198 location: unsafe { (*self_local).location },
199 }));
200
201 unsafe {
202 (*(signature_scope.as_ref() as *const Scope as *mut Scope))
203 .bindings
204 .insert(
205 crate::records::symbol::Symbol::from_local(self_local),
206 crate::records::binding::Binding {
207 type_id: self_type,
208 location: (*self_local).location,
209 deprecated: false,
210 deprecated_suggestion: alloc::string::String::new(),
211 documentation_symbol: None,
212 },
213 );
214 }
215
216 let def = unsafe { (*self.dfg).get_def_local(self_local) };
217 unsafe {
218 *(*(signature_scope.as_ref() as *const Scope as *mut Scope))
219 .lvalue_types
220 .get_or_insert(def) = self_type;
221 }
222 self.update_r_value_refinements_scope_ptr_def_id_type_id(
223 &signature_scope,
224 def,
225 self_type,
226 );
227 }
228 } else {
229 if !fn_ref.self_.is_null() {
230 let self_type =
231 self.fresh_type(&signature_scope, crate::enums::polarity::Polarity::Negative);
232 arg_types.push(self_type);
233 let arg_name = unsafe {
234 core::ffi::CStr::from_ptr((*fn_ref.self_).name.value).to_string_lossy()
235 };
236 arg_names.push(Some(crate::records::function_argument::FunctionArgument {
237 name: arg_name.into_owned(),
238 location: unsafe { (*fn_ref.self_).location },
239 }));
240
241 unsafe {
242 (*(signature_scope.as_ref() as *const Scope as *mut Scope))
243 .bindings
244 .insert(
245 crate::records::symbol::Symbol::from_local(fn_ref.self_),
246 crate::records::binding::Binding {
247 type_id: self_type,
248 location: (*fn_ref.self_).location,
249 deprecated: false,
250 deprecated_suggestion: alloc::string::String::new(),
251 documentation_symbol: None,
252 },
253 );
254 }
255
256 let def = unsafe { (*self.dfg).get_def_local(fn_ref.self_) };
257 unsafe {
258 *(*(signature_scope.as_ref() as *const Scope as *mut Scope))
259 .lvalue_types
260 .get_or_insert(def) = self_type;
261 }
262 self.update_r_value_refinements_scope_ptr_def_id_type_id(
263 &signature_scope,
264 def,
265 self_type,
266 );
267 }
268 }
269
270 for i in 0..fn_ref.args.size as usize {
271 if FFlag::DebugLuauUserDefinedClasses.get() && has_explicit_self && i == 0 {
272 continue;
273 }
274
275 let local_ptr = unsafe { *fn_ref.args.data.add(i) };
276 let local = unsafe { &*local_ptr };
277
278 let mut arg_ty: TypeId = core::ptr::null();
279 if !local.annotation.is_null() {
280 arg_ty = self.resolve_type(
281 (signature_scope.as_ref() as *const Scope as *mut Scope),
282 local.annotation,
283 false,
284 true,
285 crate::enums::polarity::Polarity::Negative,
286 );
287 } else {
288 if i < expected_arg_pack.head.len() {
289 arg_ty = expected_arg_pack.head[i];
290 } else {
291 arg_ty = self
292 .fresh_type(&signature_scope, crate::enums::polarity::Polarity::Negative);
293 }
294 }
295
296 arg_types.push(arg_ty);
297 let arg_name = unsafe { core::ffi::CStr::from_ptr(local.name.value).to_string_lossy() };
298 arg_names.push(Some(crate::records::function_argument::FunctionArgument {
299 name: arg_name.into_owned(),
300 location: local.location,
301 }));
302
303 let def = unsafe { (*self.dfg).get_def_local(local_ptr) };
304 unsafe {
305 (*(signature_scope.as_ref() as *const Scope as *mut Scope))
306 .bindings
307 .insert(
308 crate::records::symbol::Symbol::from_local(local_ptr),
309 crate::records::binding::Binding {
310 type_id: arg_ty,
311 location: local.location,
312 deprecated: false,
313 deprecated_suggestion: alloc::string::String::new(),
314 documentation_symbol: None,
315 },
316 );
317 *(*(signature_scope.as_ref() as *const Scope as *mut Scope))
318 .lvalue_types
319 .get_or_insert(def) = arg_ty;
320 }
321 self.update_r_value_refinements_scope_ptr_def_id_type_id(&signature_scope, def, arg_ty);
322 }
323
324 let mut vararg_pack: TypePackId = core::ptr::null();
325
326 if fn_ref.vararg {
327 if !fn_ref.vararg_annotation.is_null() {
328 vararg_pack = self.resolve_type_pack_scope_ptr_ast_type_pack_bool_bool_polarity(
329 (signature_scope.as_ref() as *const Scope as *mut Scope),
330 fn_ref.vararg_annotation,
331 false,
332 true,
333 crate::enums::polarity::Polarity::Negative,
334 );
335 } else if expected_arg_pack.tail.is_some()
336 && !unsafe {
337 crate::functions::get_type_pack::get_type_pack_id::<
338 crate::records::variadic_type_pack::VariadicTypePack,
339 >(expected_arg_pack.tail.unwrap())
340 }
341 .is_null()
342 {
343 vararg_pack = expected_arg_pack.tail.unwrap();
344 } else {
345 vararg_pack = unsafe { (*self.builtin_types).anyTypePack };
346 }
347
348 unsafe {
349 (*(signature_scope.as_ref() as *const Scope as *mut Scope)).vararg_pack =
350 Some(vararg_pack);
351 }
352 unsafe {
353 (*(body_scope.as_ref() as *const Scope as *mut Scope)).vararg_pack =
354 Some(vararg_pack);
355 }
356 } else {
357 vararg_pack = unsafe {
358 (*self.arena).add_type_pack_t(
359 crate::records::variadic_type_pack::VariadicTypePack {
360 ty: unsafe { (*self.builtin_types).anyType },
361 hidden: true,
362 },
363 )
364 };
365
366 unsafe {
367 (*(signature_scope.as_ref() as *const Scope as *mut Scope)).vararg_pack = None;
368 }
369 unsafe {
370 (*(body_scope.as_ref() as *const Scope as *mut Scope)).vararg_pack = None;
371 }
372 }
373
374 LUAU_ASSERT!(!vararg_pack.is_null());
375
376 if !fn_ref.self_.is_null() {
377 generic_types.push(arg_types[0]);
378 }
379
380 let mut type_index: usize = if !fn_ref.self_.is_null() { 1 } else { 0 };
381 for i in 0..fn_ref.args.size as usize {
382 let ast_arg = unsafe { *fn_ref.args.data.add(i) };
383 let arg_ty = arg_types[type_index];
384 if unsafe { (*ast_arg).annotation.is_null() } {
385 generic_types.push(arg_ty);
386 }
387 type_index += 1;
388 }
389
390 vararg_pack =
391 unsafe { crate::functions::follow_type_pack::follow_type_pack_id(vararg_pack) };
392 return_type =
393 unsafe { crate::functions::follow_type_pack::follow_type_pack_id(return_type) };
394 if fn_ref.vararg_annotation.is_null() {
395 generic_type_packs.push(vararg_pack);
396 }
397 if fn_ref.return_annotation.is_null() {
398 generic_type_packs.push(return_type);
399 }
400
401 if !fn_ref.return_annotation.is_null() {
402 let annotated_ret_type = self
403 .resolve_type_pack_scope_ptr_ast_type_pack_bool_bool_polarity(
404 (signature_scope.as_ref() as *const Scope as *mut Scope),
405 fn_ref.return_annotation,
406 false,
407 true,
408 crate::enums::polarity::Polarity::Negative,
409 );
410 unsafe {
411 crate::functions::emplace_type_pack::emplace_type_pack(
412 crate::functions::as_mutable_type_pack::as_mutable_type_pack_id(return_type),
413 TypePackVariant::Bound(annotated_ret_type),
414 );
415 }
416 } else if !expected_function.is_null() {
417 unsafe {
418 crate::functions::emplace_type_pack::emplace_type_pack(
419 crate::functions::as_mutable_type_pack::as_mutable_type_pack_id(return_type),
420 TypePackVariant::Bound((*expected_function).ret_types),
421 );
422 }
423 }
424
425 let mut actual_function = crate::records::function_type::FunctionType::function_type_new(
426 unsafe {
427 (*self.arena).add_type_pack_vector_type_id_optional_type_pack_id(
428 core::mem::take(&mut arg_types),
429 Some(vararg_pack),
430 )
431 },
432 return_type,
433 None,
434 if FFlag::DebugLuauUserDefinedClasses.get() {
435 has_self
436 } else {
437 !fn_ref.self_.is_null()
438 },
439 );
440 actual_function.generics = generic_types;
441 actual_function.generic_packs = generic_type_packs;
442 actual_function.arg_names = arg_names;
443
444 let defn = crate::records::function_definition::FunctionDefinition {
445 definition_module_name: Some(self.module.as_ref().unwrap().name.clone()),
446 definition_location: fn_ref.base.base.location,
447 vararg_location: if fn_ref.vararg {
448 Some(fn_ref.vararg_location)
449 } else {
450 None
451 },
452 original_name_location: original_name
453 .unwrap_or(Location::with_length(fn_ref.base.base.location.begin, 0)),
454 };
455 actual_function.definition = Some(defn);
456
457 let actual_function_type = unsafe { (*self.arena).add_type(actual_function) };
458 LUAU_ASSERT!(!actual_function_type.is_null());
459 unsafe {
460 let module_ptr = alloc::sync::Arc::as_ptr(self.module.as_ref().unwrap())
461 as *mut crate::records::module::Module;
462 *(*module_ptr)
463 .ast_types
464 .get_or_insert(fn_node as *const AstExpr) = actual_function_type;
465 }
466
467 if let Some(et) = expected_type_opt {
468 if !unsafe { crate::functions::get_type_alt_j::get_type_id::<crate::records::free_type::FreeType>(et) }.is_null() {
469 crate::functions::bind_free_type::bind_free_type(et, actual_function_type);
470 }
471 }
472
473 *self
474 .scope_to_function
475 .get_or_insert(signature_scope.as_ref() as *const Scope as *mut Scope) =
476 actual_function_type;
477
478 FunctionSignature {
479 signature: actual_function_type,
480 signature_scope,
481 body_scope,
482 }
483 }
484}