1use crate::enums::subtyping_suppression_policy::SubtypingSuppressionPolicy;
2use crate::enums::table_state::TableState;
3use crate::enums::type_field::TypeField;
4use crate::functions::assert_reasoning_valid_subtyping::assert_reasoning_valid;
5use crate::functions::follow_type::follow_type_id;
6use crate::functions::get_2::get2;
7use crate::functions::get_type_alt_j::get_type_id;
8use crate::functions::subsumes_scope::subsumes;
9use crate::methods::subtyping_bind_generic::dense_hash_map_find_no_default;
10use crate::records::any_type::AnyType;
11use crate::records::blocked_type::BlockedType;
12use crate::records::error_type::ErrorType;
13use crate::records::extern_type::ExternType;
14use crate::records::free_type::FreeType;
15use crate::records::function_type::FunctionType;
16use crate::records::generic_type::GenericType;
17use crate::records::intersection_type::IntersectionType;
18use crate::records::metatable_type::MetatableType;
19use crate::records::negation_type::NegationType;
20use crate::records::never_type::NeverType;
21use crate::records::primitive_type::{PrimitiveType, Type as PrimType};
22use crate::records::scope::Scope;
23use crate::records::singleton_type::SingletonType;
24use crate::records::subtype_constraint::SubtypeConstraint;
25use crate::records::subtyping::Subtyping;
26use crate::records::subtyping_environment::SubtypingEnvironment;
27use crate::records::subtyping_result::SubtypingResult;
28use crate::records::table_type::TableType;
29use crate::records::type_function_instance_type::TypeFunctionInstanceType;
30use crate::records::union_type::UnionType;
31use crate::records::unknown_type::UnknownType;
32use crate::type_aliases::component::Component;
33use crate::type_aliases::constraint_v::ConstraintV;
34use crate::type_aliases::type_id::TypeId;
35
36impl Subtyping {
37 pub fn is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
38 &mut self,
39 env: &mut SubtypingEnvironment,
40 sub_ty: TypeId,
41 super_ty: TypeId,
42 scope: *mut Scope,
43 ) -> SubtypingResult {
44 let recursion_count_ptr =
46 unsafe { &mut (*(*self.normalizer).shared_state).counters.recursion_count as *mut i32 };
47 let mut nerl =
48 crate::records::non_exceptional_recursion_limiter::NonExceptionalRecursionLimiter {
49 base: unsafe { core::mem::zeroed() },
50 native_stack_guard: unsafe { core::mem::zeroed() },
51 };
52 nerl.non_exceptional_recursion_limiter_non_exceptional_recursion_limiter(
53 recursion_count_ptr as *mut core::ffi::c_int,
54 );
55 if !nerl.is_ok(luaur_common::DFInt::LuauSubtypingRecursionLimit.get() as core::ffi::c_int) {
56 return SubtypingResult {
57 is_subtype: false,
58 normalization_too_complex: true,
59 ..Default::default()
60 };
61 }
62 let _nerl = nerl;
63
64 env.iteration_count += 1;
65 let iteration_limit = luaur_common::FInt::LuauSubtypingIterationLimit.get() as i32;
66 if iteration_limit > 0 && env.iteration_count >= iteration_limit {
67 return SubtypingResult {
68 is_subtype: false,
69 normalization_too_complex: true,
70 ..Default::default()
71 };
72 }
73
74 let mut sub_ty = unsafe { follow_type_id(sub_ty) };
75 let mut super_ty = unsafe { follow_type_id(super_ty) };
76
77 if let Some(sub_it) = env.try_find_substitution(sub_ty) {
78 if !sub_it.is_null() {
79 sub_ty = sub_it;
80 }
81 }
82
83 if let Some(super_it) = env.try_find_substitution(super_ty) {
84 if !super_it.is_null() {
85 sub_ty = super_it;
88 }
89 }
90
91 if let Some(cached_result) = self.result_cache.find(&(sub_ty, super_ty)) {
92 return cached_result.clone();
93 }
94
95 if let Some(cached_result) = env.try_find_subtyping_result((sub_ty, super_ty)) {
96 return cached_result.clone();
97 }
98
99 if sub_ty == super_ty {
101 return SubtypingResult {
102 is_subtype: true,
103 ..Default::default()
104 };
105 }
106
107 let type_pair = (sub_ty, super_ty);
108 let fresh = {
110 let entry = self.seen_types.get_or_insert(type_pair);
111 let fresh = !*entry;
112 if fresh {
113 *entry = true;
114 }
115 fresh
116 };
117 if !fresh {
118 let mut res = SubtypingResult::default();
121 res.is_subtype = true;
122 res.is_cacheable = false;
123
124 *env.seen_set_cache.get_or_insert(type_pair) = res.clone();
125
126 return res;
127 }
128
129 let mut result = SubtypingResult::default();
134
135 let pair_ff = get2::<FreeType, FreeType, _>(sub_ty, super_ty);
136 if !pair_ff.first.is_null() {
137 result = SubtypingResult {
140 is_subtype: true,
141 ..Default::default()
142 };
143 result.with_assumed_constraint(ConstraintV::Subtype(SubtypeConstraint {
144 sub_type: sub_ty,
145 super_type: super_ty,
146 }));
147 } else if let Some(super_free) = unsafe { get_type_id::<FreeType>(super_ty).as_ref() } {
148 result = self.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
150 env,
151 sub_ty,
152 super_free.upper_bound,
153 scope,
154 );
155
156 if result.is_subtype {
157 result.with_assumed_constraint(ConstraintV::Subtype(SubtypeConstraint {
158 sub_type: sub_ty,
159 super_type: super_ty,
160 }));
161 }
162 } else if let Some(sub_free) = unsafe { get_type_id::<FreeType>(sub_ty).as_ref() } {
163 if self
165 .is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
166 env,
167 sub_free.lower_bound,
168 super_ty,
169 scope,
170 )
171 .is_subtype
172 {
173 result = SubtypingResult {
174 is_subtype: true,
175 ..Default::default()
176 };
177 result.with_assumed_constraint(ConstraintV::Subtype(SubtypeConstraint {
178 sub_type: sub_ty,
179 super_type: super_ty,
180 }));
181 } else {
182 result = SubtypingResult {
183 is_subtype: false,
184 ..Default::default()
185 };
186 }
187 } else if unsafe {
188 !get_type_id::<BlockedType>(sub_ty).is_null()
189 || !get_type_id::<BlockedType>(super_ty).is_null()
190 } {
191 result = SubtypingResult {
192 is_subtype: true,
193 ..Default::default()
194 };
195 result.with_assumed_constraint(ConstraintV::Subtype(SubtypeConstraint {
196 sub_type: sub_ty,
197 super_type: super_ty,
198 }));
199 }
200 else if let Some(sub_generic) = unsafe { get_type_id::<GenericType>(sub_ty).as_ref() }
202 .filter(|g| subsumes(g.scope, scope))
203 {
204 let _ = sub_generic;
205 self.seen_set_erase(type_pair);
206 return self.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
207 env,
208 unsafe { (*self.builtin_types).neverType },
209 super_ty,
210 scope,
211 );
212 } else if let Some(super_generic) = unsafe { get_type_id::<GenericType>(super_ty).as_ref() }
213 .filter(|g| subsumes(g.scope, scope))
214 {
215 let _ = super_generic;
216 self.seen_set_erase(type_pair);
217 return self.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
218 env,
219 sub_ty,
220 unsafe { (*self.builtin_types).unknownType },
221 scope,
222 );
223 } else if unsafe { !get_type_id::<AnyType>(super_ty).is_null() } {
224 result = SubtypingResult {
225 is_subtype: true,
226 ..Default::default()
227 };
228 }
229 else if unsafe {
231 !get_type_id::<AnyType>(sub_ty).is_null()
232 && !get_type_id::<UnknownType>(super_ty).is_null()
233 } {
234 result = SubtypingResult {
235 is_subtype: true,
236 ..Default::default()
237 };
238 } else if unsafe { !get_type_id::<AnyType>(sub_ty).is_null() } {
239 result = self.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
241 env,
242 unsafe { (*self.builtin_types).unknownType },
243 super_ty,
244 scope,
245 );
246 let err_part = self
247 .is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
248 env,
249 unsafe { (*self.builtin_types).errorType },
250 super_ty,
251 scope,
252 );
253 result.and_also(err_part, SubtypingSuppressionPolicy::Any);
254 result.is_error_suppressing = true;
255 } else if unsafe {
256 !get_type_id::<UnknownType>(super_ty).is_null()
257 && get_type_id::<UnionType>(sub_ty).is_null()
258 && get_type_id::<IntersectionType>(sub_ty).is_null()
259 } {
260 let error_suppressing = unsafe { !get_type_id::<ErrorType>(sub_ty).is_null() };
261 result.is_subtype = !error_suppressing;
262 result.is_error_suppressing = error_suppressing;
263 } else if unsafe { !get_type_id::<NeverType>(sub_ty).is_null() } {
264 result = SubtypingResult {
265 is_subtype: true,
266 ..Default::default()
267 };
268 } else if unsafe { !get_type_id::<ErrorType>(super_ty).is_null() } {
269 result = SubtypingResult {
270 is_subtype: false,
271 ..Default::default()
272 };
273 } else if unsafe { !get_type_id::<ErrorType>(sub_ty).is_null() } {
274 result = SubtypingResult {
275 is_subtype: true,
276 ..Default::default()
277 };
278 result.is_error_suppressing = true;
279 } else if unsafe { !get_type_id::<TypeFunctionInstanceType>(sub_ty).is_null() } {
280 let mut sub_type_function_instance =
281 unsafe { get_type_id::<TypeFunctionInstanceType>(sub_ty) };
282 let mut mapped_generics_applied = false;
283 if let Some(subst_sub_ty) =
284 env.apply_mapped_generics(self.builtin_types, self.arena, sub_ty, self.ice_reporter)
285 {
286 mapped_generics_applied = subst_sub_ty != sub_ty;
287 sub_type_function_instance =
288 unsafe { get_type_id::<TypeFunctionInstanceType>(subst_sub_ty) };
289 }
290
291 result = self
292 .is_covariant_with_subtyping_environment_type_function_instance_type_type_id_not_null_scope(
293 env,
294 unsafe { &*sub_type_function_instance },
295 super_ty,
296 scope,
297 );
298 result.is_cacheable = !mapped_generics_applied;
299 } else if unsafe { !get_type_id::<TypeFunctionInstanceType>(super_ty).is_null() } {
300 let mut super_type_function_instance =
301 unsafe { get_type_id::<TypeFunctionInstanceType>(super_ty) };
302 let mut mapped_generics_applied = false;
303 if let Some(subst_super_ty) = env.apply_mapped_generics(
304 self.builtin_types,
305 self.arena,
306 super_ty,
307 self.ice_reporter,
308 ) {
309 mapped_generics_applied = subst_super_ty != super_ty;
310 super_type_function_instance =
311 unsafe { get_type_id::<TypeFunctionInstanceType>(subst_super_ty) };
312 }
313
314 result = self
315 .is_covariant_with_subtyping_environment_type_id_type_function_instance_type_not_null_scope(
316 env,
317 sub_ty,
318 unsafe { &*super_type_function_instance },
319 scope,
320 );
321 result.is_cacheable = !mapped_generics_applied;
322 } else if unsafe {
323 !get_type_id::<GenericType>(sub_ty).is_null()
324 || !get_type_id::<GenericType>(super_ty).is_null()
325 } {
326 let sub_has_bounds = dense_hash_map_find_no_default(&env.mapped_generics, &sub_ty)
327 .map_or(false, |b| !b.is_empty());
328 let super_has_bounds = dense_hash_map_find_no_default(&env.mapped_generics, &super_ty)
329 .map_or(false, |b| !b.is_empty());
330 if sub_has_bounds {
331 let ok = self.bind_generic(env, sub_ty, super_ty);
332 result.is_subtype = ok;
333 result.is_cacheable = false;
334 } else if super_has_bounds {
335 let ok = self.bind_generic(env, sub_ty, super_ty);
336 result.is_subtype = ok;
337 result.is_cacheable = false;
338 }
339 } else if let Some(sub_union) = unsafe { get_type_id::<UnionType>(sub_ty).as_ref() } {
340 result = self
341 .is_covariant_with_subtyping_environment_union_type_type_id_not_null_scope(
342 env, sub_union, super_ty, scope,
343 );
344 } else if let Some(super_union) = unsafe { get_type_id::<UnionType>(super_ty).as_ref() } {
345 result = self
346 .is_covariant_with_subtyping_environment_type_id_union_type_not_null_scope(
347 env,
348 sub_ty,
349 super_union,
350 scope,
351 );
352 if !result.is_subtype && !result.normalization_too_complex {
353 result = self.try_semantic_subtyping(env, sub_ty, super_ty, scope, &mut result);
354 }
355 } else if let Some(super_intersection) =
356 unsafe { get_type_id::<IntersectionType>(super_ty).as_ref() }
357 {
358 result = self
359 .is_covariant_with_subtyping_environment_type_id_intersection_type_not_null_scope(
360 env,
361 sub_ty,
362 super_intersection,
363 scope,
364 );
365 } else if let Some(sub_intersection) =
366 unsafe { get_type_id::<IntersectionType>(sub_ty).as_ref() }
367 {
368 result = self
369 .is_covariant_with_subtyping_environment_intersection_type_type_id_not_null_scope(
370 env,
371 sub_intersection,
372 super_ty,
373 scope,
374 );
375 if !result.is_subtype && !result.normalization_too_complex {
376 result = self.try_semantic_subtyping(env, sub_ty, super_ty, scope, &mut result);
377 }
378 } else if {
379 let p = get2::<NegationType, NegationType, _>(sub_ty, super_ty);
380 !p.first.is_null()
381 } {
382 let p = get2::<NegationType, NegationType, _>(sub_ty, super_ty);
383 result = self
386 .is_contravariant_with_subtyping_environment_sub_ty_super_ty_not_null_scope(
387 env,
388 unsafe { (*p.first).ty },
389 unsafe { (*p.second).ty },
390 scope,
391 );
392 result.with_both_component(Component::TypeField(TypeField::Negated));
393 } else if let Some(sub_negation) = unsafe { get_type_id::<NegationType>(sub_ty).as_ref() } {
394 result = self
395 .is_covariant_with_subtyping_environment_negation_type_type_id_not_null_scope(
396 env,
397 sub_negation,
398 super_ty,
399 scope,
400 );
401 if !result.is_subtype && !result.normalization_too_complex {
402 result = self.try_semantic_subtyping(env, sub_ty, super_ty, scope, &mut result);
403 }
404 } else if let Some(super_negation) =
405 unsafe { get_type_id::<NegationType>(super_ty).as_ref() }
406 {
407 result = self
408 .is_covariant_with_subtyping_environment_type_id_negation_type_not_null_scope(
409 env,
410 sub_ty,
411 super_negation,
412 scope,
413 );
414 if !result.is_subtype && !result.normalization_too_complex {
415 result = self.try_semantic_subtyping(env, sub_ty, super_ty, scope, &mut result);
416 }
417 } else if {
418 let p = get2::<PrimitiveType, PrimitiveType, _>(sub_ty, super_ty);
419 !p.first.is_null()
420 } {
421 let p = get2::<PrimitiveType, PrimitiveType, _>(sub_ty, super_ty);
422 result = self
423 .is_covariant_with_subtyping_environment_primitive_type_primitive_type_not_null_scope(
424 env,
425 unsafe { &*p.first },
426 unsafe { &*p.second },
427 scope,
428 );
429 } else if {
430 let p = get2::<SingletonType, PrimitiveType, _>(sub_ty, super_ty);
431 !p.first.is_null()
432 } {
433 let p = get2::<SingletonType, PrimitiveType, _>(sub_ty, super_ty);
434 result = self
435 .is_covariant_with_subtyping_environment_singleton_type_primitive_type_not_null_scope(
436 env,
437 unsafe { &*p.first },
438 unsafe { &*p.second },
439 scope,
440 );
441 } else if {
442 let p = get2::<SingletonType, SingletonType, _>(sub_ty, super_ty);
443 !p.first.is_null()
444 } {
445 let p = get2::<SingletonType, SingletonType, _>(sub_ty, super_ty);
446 result = self
447 .is_covariant_with_subtyping_environment_singleton_type_singleton_type_not_null_scope(
448 env,
449 unsafe { &*p.first },
450 unsafe { &*p.second },
451 scope,
452 );
453 } else if {
454 let p = get2::<FunctionType, PrimitiveType, _>(sub_ty, super_ty);
455 !p.first.is_null()
456 } {
457 let p = get2::<FunctionType, PrimitiveType, _>(sub_ty, super_ty);
458 let _sub_function = p.first;
459 let super_primitive = p.second;
460 result.is_subtype = unsafe { (*super_primitive).r#type == PrimType::Function };
461 } else if {
462 let p = get2::<FunctionType, FunctionType, _>(sub_ty, super_ty);
463 !p.first.is_null()
464 } {
465 let p = get2::<FunctionType, FunctionType, _>(sub_ty, super_ty);
466 result = self
467 .is_covariant_with_subtyping_environment_function_type_function_type_not_null_scope(
468 env,
469 unsafe { &*p.first },
470 unsafe { &*p.second },
471 scope,
472 );
473 } else if {
474 let p = get2::<TableType, TableType, _>(sub_ty, super_ty);
475 !p.first.is_null()
476 } {
477 let p = get2::<TableType, TableType, _>(sub_ty, super_ty);
478 let force_covariant_test =
479 !self.unique_types.is_null() && unsafe { (*self.unique_types).contains(&sub_ty) };
480 result = if luaur_common::FFlag::LuauSubtypingTablesHasBetterErrorSuppression.get() {
481 self.is_covariant_with_subtyping_environment_table_type_table_type_bool_not_null_scope(
482 env,
483 unsafe { &*p.first },
484 unsafe { &*p.second },
485 force_covariant_test,
486 scope,
487 )
488 } else {
489 self.is_covariant_with_deprecated(
490 env,
491 unsafe { &*p.first },
492 unsafe { &*p.second },
493 force_covariant_test,
494 scope,
495 )
496 };
497 if result.is_subtype
498 && unsafe { (*p.first).indexer.is_none() }
499 && unsafe { (*p.second).indexer.is_some() }
500 && unsafe { (*p.first).state != TableState::Sealed }
501 {
502 result.with_assumed_constraint(ConstraintV::Subtype(SubtypeConstraint {
504 sub_type: sub_ty,
505 super_type: super_ty,
506 }));
507 }
508 } else if {
509 let p = get2::<MetatableType, MetatableType, _>(sub_ty, super_ty);
510 !p.first.is_null()
511 } {
512 let p = get2::<MetatableType, MetatableType, _>(sub_ty, super_ty);
513 result = self
514 .is_covariant_with_subtyping_environment_metatable_type_metatable_type_not_null_scope(
515 env,
516 unsafe { &*p.first },
517 unsafe { &*p.second },
518 scope,
519 );
520 } else if {
521 let p = get2::<MetatableType, TableType, _>(sub_ty, super_ty);
522 !p.first.is_null()
523 } {
524 let p = get2::<MetatableType, TableType, _>(sub_ty, super_ty);
525 result = self
526 .is_covariant_with_subtyping_environment_metatable_type_table_type_not_null_scope(
527 env,
528 unsafe { &*p.first },
529 unsafe { &*p.second },
530 scope,
531 );
532 } else if luaur_common::FFlag::LuauTableFreezeCheckIsSubtype.get() && {
533 let p = get2::<MetatableType, PrimitiveType, _>(sub_ty, super_ty);
534 !p.first.is_null()
535 } {
536 let p = get2::<MetatableType, PrimitiveType, _>(sub_ty, super_ty);
537 result = self
538 .is_covariant_with_subtyping_environment_metatable_type_primitive_type_not_null_scope(
539 env,
540 unsafe { &*p.first },
541 unsafe { &*p.second },
542 scope,
543 );
544 } else if {
545 let p = get2::<ExternType, ExternType, _>(sub_ty, super_ty);
546 !p.first.is_null()
547 } {
548 let p = get2::<ExternType, ExternType, _>(sub_ty, super_ty);
549 result = self
550 .is_covariant_with_subtyping_environment_extern_type_extern_type_not_null_scope(
551 env,
552 unsafe { &*p.first },
553 unsafe { &*p.second },
554 scope,
555 );
556 } else if {
557 let p = get2::<ExternType, TableType, _>(sub_ty, super_ty);
558 !p.first.is_null()
559 } {
560 let p = get2::<ExternType, TableType, _>(sub_ty, super_ty);
561 result = self
562 .is_covariant_with_subtyping_environment_type_id_extern_type_type_id_table_type_not_null_scope(
563 env,
564 sub_ty,
565 unsafe { &*p.first },
566 super_ty,
567 unsafe { &*p.second },
568 scope,
569 );
570 } else if {
571 let p = get2::<TableType, PrimitiveType, _>(sub_ty, super_ty);
572 !p.first.is_null()
573 } {
574 let p = get2::<TableType, PrimitiveType, _>(sub_ty, super_ty);
575 result = self
576 .is_covariant_with_subtyping_environment_table_type_primitive_type_not_null_scope(
577 env,
578 unsafe { &*p.first },
579 unsafe { &*p.second },
580 scope,
581 );
582 } else if {
583 let p = get2::<PrimitiveType, TableType, _>(sub_ty, super_ty);
584 !p.first.is_null()
585 } {
586 let p = get2::<PrimitiveType, TableType, _>(sub_ty, super_ty);
587 result = self
588 .is_covariant_with_subtyping_environment_primitive_type_table_type_not_null_scope(
589 env,
590 unsafe { &*p.first },
591 unsafe { &*p.second },
592 scope,
593 );
594 } else if {
595 let p = get2::<SingletonType, TableType, _>(sub_ty, super_ty);
596 !p.first.is_null()
597 } {
598 let p = get2::<SingletonType, TableType, _>(sub_ty, super_ty);
599 result = self
600 .is_covariant_with_subtyping_environment_singleton_type_table_type_not_null_scope(
601 env,
602 unsafe { &*p.first },
603 unsafe { &*p.second },
604 scope,
605 );
606 }
607
608 assert_reasoning_valid(sub_ty, super_ty, &result, self.builtin_types, self.arena);
609
610 self.seen_set_erase(type_pair);
612
613 self.cache(env, result, sub_ty, super_ty)
614 }
615
616 #[inline]
619 fn seen_set_erase(&mut self, type_pair: (TypeId, TypeId)) {
620 let entry = self.seen_types.get_or_insert(type_pair);
621 if *entry {
622 *entry = false;
623 }
624 }
625}