1use crate::AssignabilityChecker;
14use crate::TypeDatabase;
15use crate::db::QueryDatabase;
16use crate::def::DefId;
17use crate::diagnostics::{DynSubtypeTracer, SubtypeFailureReason};
18#[cfg(test)]
19use crate::types::*;
20use crate::types::{
21 IntrinsicKind, LiteralValue, ObjectFlags, ObjectShape, SymbolRef, TypeData, TypeId, TypeListId,
22};
23use crate::visitor::{
24 TypeVisitor, application_id, array_element_type, callable_shape_id, conditional_type_id,
25 enum_components, function_shape_id, intersection_list_id, intrinsic_kind, is_this_type,
26 keyof_inner_type, lazy_def_id, literal_value, mapped_type_id, object_shape_id,
27 object_with_index_shape_id, readonly_inner_type, ref_symbol, template_literal_id,
28 tuple_list_id, type_param_info, type_query_symbol, union_list_id, unique_symbol_ref,
29};
30use rustc_hash::{FxHashMap, FxHashSet};
31use tsz_common::limits;
32
33pub(crate) const MAX_SUBTYPE_DEPTH: u32 = limits::MAX_SUBTYPE_DEPTH;
37pub(crate) const INTERSECTION_OBJECT_FAST_PATH_THRESHOLD: usize = 8;
38
39#[derive(Copy, Clone, Debug, PartialEq, Eq)]
41pub enum SubtypeResult {
42 True,
44 False,
46 CycleDetected,
51 DepthExceeded,
59}
60
61impl SubtypeResult {
62 pub const fn is_true(self) -> bool {
63 matches!(self, Self::True | Self::CycleDetected)
64 }
65
66 pub const fn is_false(self) -> bool {
67 matches!(self, Self::False)
68 }
69}
70
71fn is_disjoint_unit_type(types: &dyn TypeDatabase, ty: TypeId) -> bool {
79 match types.lookup(ty) {
80 Some(TypeData::Literal(_) | TypeData::UniqueSymbol(_)) => true,
81 _ => false,
84 }
85}
86
87#[derive(Copy, Clone, Debug, PartialEq, Eq)]
89pub enum AnyPropagationMode {
90 All,
92 TopLevelOnly,
94}
95
96impl AnyPropagationMode {
97 #[inline]
98 pub(crate) const fn allows_any_at_depth(self, depth: u32) -> bool {
99 match self {
100 Self::All => true,
101 Self::TopLevelOnly => depth == 0,
102 }
103 }
104}
105
106pub use crate::type_resolver::{NoopResolver, TypeEnvironment, TypeResolver};
108
109pub use crate::subtype_visitor::SubtypeVisitor;
111
112pub struct SubtypeChecker<'a, R: TypeResolver = NoopResolver> {
115 pub(crate) interner: &'a dyn TypeDatabase,
116 pub(crate) query_db: Option<&'a dyn QueryDatabase>,
119 pub(crate) resolver: &'a R,
120 pub(crate) guard: crate::recursion::RecursionGuard<(TypeId, TypeId)>,
122 pub(crate) seen_refs: FxHashSet<(SymbolRef, SymbolRef)>,
126 pub(crate) def_guard: crate::recursion::RecursionGuard<(DefId, DefId)>,
129 sym_visiting: FxHashSet<(tsz_binder::SymbolId, tsz_binder::SymbolId)>,
135 pub strict_function_types: bool,
138 pub allow_void_return: bool,
140 pub allow_bivariant_rest: bool,
143 pub bypass_evaluation: bool,
147 pub max_depth: u32,
151 pub allow_bivariant_param_count: bool,
153 pub exact_optional_property_types: bool,
156 pub strict_null_checks: bool,
159 pub no_unchecked_indexed_access: bool,
162 pub disable_method_bivariance: bool,
165 pub inheritance_graph: Option<&'a crate::inheritance::InheritanceGraph>,
168 pub is_class_symbol: Option<&'a dyn Fn(SymbolRef) -> bool>,
171 pub any_propagation: AnyPropagationMode,
173 pub(crate) eval_cache: FxHashMap<(TypeId, bool), TypeId>,
178 pub tracer: Option<&'a mut dyn DynSubtypeTracer>,
182}
183
184impl<'a> SubtypeChecker<'a, NoopResolver> {
185 pub fn new(interner: &'a dyn TypeDatabase) -> Self {
187 static NOOP: NoopResolver = NoopResolver;
188 SubtypeChecker {
189 interner,
190 query_db: None,
191 resolver: &NOOP,
192 guard: crate::recursion::RecursionGuard::with_profile(
193 crate::recursion::RecursionProfile::SubtypeCheck,
194 ),
195 seen_refs: FxHashSet::default(),
196 def_guard: crate::recursion::RecursionGuard::with_profile(
197 crate::recursion::RecursionProfile::SubtypeCheck,
198 ),
199 sym_visiting: FxHashSet::default(),
200 strict_function_types: true, allow_void_return: false,
202 allow_bivariant_rest: false,
203 allow_bivariant_param_count: false,
204 exact_optional_property_types: false,
205 strict_null_checks: true,
206 no_unchecked_indexed_access: false,
207 disable_method_bivariance: false,
208 inheritance_graph: None,
209 is_class_symbol: None,
210 any_propagation: AnyPropagationMode::All,
211 bypass_evaluation: false,
212 max_depth: MAX_SUBTYPE_DEPTH,
213 eval_cache: FxHashMap::default(),
214 tracer: None,
215 }
216 }
217}
218
219impl<'a, R: TypeResolver> SubtypeChecker<'a, R> {
220 pub fn with_resolver(interner: &'a dyn TypeDatabase, resolver: &'a R) -> Self {
222 SubtypeChecker {
223 interner,
224 query_db: None,
225 resolver,
226 guard: crate::recursion::RecursionGuard::with_profile(
227 crate::recursion::RecursionProfile::SubtypeCheck,
228 ),
229 seen_refs: FxHashSet::default(),
230 def_guard: crate::recursion::RecursionGuard::with_profile(
231 crate::recursion::RecursionProfile::SubtypeCheck,
232 ),
233 sym_visiting: FxHashSet::default(),
234 strict_function_types: true,
235 allow_void_return: false,
236 allow_bivariant_rest: false,
237 allow_bivariant_param_count: false,
238 exact_optional_property_types: false,
239 strict_null_checks: true,
240 no_unchecked_indexed_access: false,
241 disable_method_bivariance: false,
242 inheritance_graph: None,
243 is_class_symbol: None,
244 any_propagation: AnyPropagationMode::All,
245 bypass_evaluation: false,
246 max_depth: MAX_SUBTYPE_DEPTH,
247 eval_cache: FxHashMap::default(),
248 tracer: None,
249 }
250 }
251
252 pub const fn with_inheritance_graph(
254 mut self,
255 graph: &'a crate::inheritance::InheritanceGraph,
256 ) -> Self {
257 self.inheritance_graph = Some(graph);
258 self
259 }
260
261 pub fn with_class_check(mut self, check: &'a dyn Fn(SymbolRef) -> bool) -> Self {
263 self.is_class_symbol = Some(check);
264 self
265 }
266
267 pub const fn with_any_propagation_mode(mut self, mode: AnyPropagationMode) -> Self {
269 self.any_propagation = mode;
270 self
271 }
272
273 pub fn with_tracer(mut self, tracer: &'a mut dyn DynSubtypeTracer) -> Self {
276 self.tracer = Some(tracer);
277 self
278 }
279
280 pub fn with_query_db(mut self, db: &'a dyn QueryDatabase) -> Self {
283 self.query_db = Some(db);
284 self
285 }
286
287 pub const fn with_strict_null_checks(mut self, strict_null_checks: bool) -> Self {
290 self.strict_null_checks = strict_null_checks;
291 self
292 }
293
294 #[inline]
302 pub fn reset(&mut self) {
303 self.guard.reset();
304 self.seen_refs.clear();
305 self.def_guard.reset();
306 self.sym_visiting.clear();
307 self.eval_cache.clear();
308 }
309
310 pub const fn depth_exceeded(&self) -> bool {
312 self.guard.is_exceeded()
313 }
314
315 pub(crate) const fn apply_flags(mut self, flags: u16) -> Self {
328 self.strict_null_checks = (flags & (1 << 0)) != 0;
329 self.strict_function_types = (flags & (1 << 1)) != 0;
330 self.exact_optional_property_types = (flags & (1 << 2)) != 0;
331 self.no_unchecked_indexed_access = (flags & (1 << 3)) != 0;
332 self.disable_method_bivariance = (flags & (1 << 4)) != 0;
333 self.allow_void_return = (flags & (1 << 5)) != 0;
334 self.allow_bivariant_rest = (flags & (1 << 6)) != 0;
335 self.allow_bivariant_param_count = (flags & (1 << 7)) != 0;
336 self
337 }
338
339 pub(crate) fn resolve_ref_type(&self, type_id: TypeId) -> TypeId {
340 if let Some(def_id) = lazy_def_id(self.interner, type_id) {
342 return self
343 .resolver
344 .resolve_lazy(def_id, self.interner)
345 .unwrap_or(type_id);
346 }
347
348 if let Some(symbol) = ref_symbol(self.interner, type_id) {
350 self.resolver
351 .resolve_symbol_ref(symbol, self.interner)
352 .unwrap_or(type_id)
353 } else {
354 type_id
355 }
356 }
357
358 pub(crate) fn resolve_lazy_type(&self, type_id: TypeId) -> TypeId {
359 if let Some(def_id) = lazy_def_id(self.interner, type_id) {
360 self.resolver
361 .resolve_lazy(def_id, self.interner)
362 .unwrap_or(type_id)
363 } else {
364 type_id
365 }
366 }
367
368 pub fn check_subtype(&mut self, source: TypeId, target: TypeId) -> SubtypeResult {
373 let allow_any = self.any_propagation.allows_any_at_depth(self.guard.depth());
378 let mut source = source;
379 let mut target = target;
380 if !allow_any {
381 if source == TypeId::ANY {
382 source = TypeId::STRICT_ANY;
385 }
386 if target == TypeId::ANY {
387 target = TypeId::STRICT_ANY;
388 }
389 }
390
391 if source == target {
393 return SubtypeResult::True;
394 }
395
396 if !self.bypass_evaluation
404 && let Some(db) = self.query_db
405 {
406 let source_canon = db.canonical_id(source);
407 let target_canon = db.canonical_id(target);
408 if source_canon == target_canon {
409 return SubtypeResult::True;
410 }
411 }
412
413 if allow_any && (source == TypeId::ANY || source == TypeId::STRICT_ANY) {
415 return SubtypeResult::True;
416 }
417
418 if allow_any && (target == TypeId::ANY || target == TypeId::STRICT_ANY) {
420 return SubtypeResult::True;
421 }
422
423 if !allow_any
426 && (source == TypeId::ANY || source == TypeId::STRICT_ANY)
427 && (target == TypeId::ANY || target == TypeId::STRICT_ANY || target == TypeId::UNKNOWN)
428 {
429 return SubtypeResult::True;
430 }
431 if !allow_any && (target == TypeId::ANY || target == TypeId::STRICT_ANY) {
433 return SubtypeResult::True;
434 }
435 if target == TypeId::UNKNOWN {
439 return SubtypeResult::True;
440 }
441
442 if source == TypeId::NEVER {
444 return SubtypeResult::True;
445 }
446
447 if source == TypeId::ERROR || target == TypeId::ERROR {
450 return SubtypeResult::True;
451 }
452
453 if is_disjoint_unit_type(self.interner, source)
456 && is_disjoint_unit_type(self.interner, target)
457 {
458 return SubtypeResult::False;
459 }
460
461 if let Some(db) = self.query_db {
468 let key = self.make_cache_key(source, target);
469 if let Some(cached) = db.lookup_subtype_cache(key) {
470 return if cached {
471 SubtypeResult::True
472 } else {
473 SubtypeResult::False
474 };
475 }
476 }
477
478 let pair = (source, target);
486
487 if self.guard.is_visiting(&(target, source)) {
489 return SubtypeResult::CycleDetected;
490 }
491
492 use crate::recursion::RecursionResult;
493 match self.guard.enter(pair) {
494 RecursionResult::Cycle => return SubtypeResult::CycleDetected,
495 RecursionResult::DepthExceeded | RecursionResult::IterationExceeded => {
496 return SubtypeResult::DepthExceeded;
497 }
498 RecursionResult::Entered => {}
499 }
500
501 let extract_def_id =
518 |interner: &dyn crate::TypeDatabase, type_id: TypeId| -> Option<DefId> {
519 if let Some(def) = lazy_def_id(interner, type_id) {
521 return Some(def);
522 }
523 if let Some((def, _)) = enum_components(interner, type_id) {
524 return Some(def);
525 }
526 if let Some(app_id) = application_id(interner, type_id) {
528 let app = interner.type_application(app_id);
529 if let Some(def) = lazy_def_id(interner, app.base) {
530 return Some(def);
531 }
532 }
533 None
534 };
535
536 let s_def_id = extract_def_id(self.interner, source);
537 let t_def_id = extract_def_id(self.interner, target);
538
539 let def_pair = if let (Some(s_def), Some(t_def)) = (s_def_id, t_def_id) {
540 if s_def == t_def
543 && application_id(self.interner, source).is_some()
544 && application_id(self.interner, target).is_some()
545 {
546 None
547 } else {
548 Some((s_def, t_def))
549 }
550 } else {
551 None
552 };
553
554 if let (Some(s_def), Some(t_def)) = (s_def_id, t_def_id) {
567 let s_sym = self.resolver.def_to_symbol_id(s_def);
568 let t_sym = self.resolver.def_to_symbol_id(t_def);
569 if let (Some(s_sid), Some(t_sid)) = (s_sym, t_sym) {
570 if self.def_guard.is_visiting_any(|&(visiting_s, visiting_t)| {
572 visiting_s != s_def
573 && visiting_t != t_def
574 && self.resolver.def_to_symbol_id(visiting_s) == Some(s_sid)
575 && self.resolver.def_to_symbol_id(visiting_t) == Some(t_sid)
576 }) {
577 self.guard.leave(pair);
578 return SubtypeResult::CycleDetected;
579 }
580 }
581 }
582
583 let def_entered = if let Some((s_def, t_def)) = def_pair {
584 if self.def_guard.is_visiting(&(t_def, s_def)) {
586 self.guard.leave(pair);
587 return SubtypeResult::CycleDetected;
588 }
589 match self.def_guard.enter((s_def, t_def)) {
590 RecursionResult::Cycle => {
591 self.guard.leave(pair);
592 return SubtypeResult::CycleDetected;
593 }
594 RecursionResult::Entered => Some((s_def, t_def)),
595 _ => None,
596 }
597 } else {
598 None
599 };
600
601 {
610 let is_object_interface_target = self
611 .resolver
612 .is_boxed_type_id(target, IntrinsicKind::Object)
613 || self
614 .resolver
615 .get_boxed_type(IntrinsicKind::Object)
616 .is_some_and(|boxed| boxed == target)
617 || lazy_def_id(self.interner, target).is_some_and(|def_id| {
618 self.resolver.is_boxed_def_id(def_id, IntrinsicKind::Object)
619 });
620 if is_object_interface_target {
621 let is_nullable = matches!(source, TypeId::NULL | TypeId::UNDEFINED | TypeId::VOID);
622 if !is_nullable {
623 let result = self.check_object_contract(source, target);
624 if let Some(dp) = def_entered {
625 self.def_guard.leave(dp);
626 }
627 self.guard.leave(pair);
628 return result;
629 }
630 }
631 }
632
633 if !self.bypass_evaluation
638 && (lazy_def_id(self.interner, target).is_some_and(|t_def| {
639 self.resolver
640 .is_boxed_def_id(t_def, IntrinsicKind::Function)
641 }) || self
642 .resolver
643 .is_boxed_type_id(target, IntrinsicKind::Function))
644 {
645 let source_eval = self.evaluate_type(source);
646 if self.is_callable_type(source_eval) {
647 if let Some(dp) = def_entered {
651 self.def_guard.leave(dp);
652 }
653 self.guard.leave(pair);
654 return SubtypeResult::True;
655 }
656 }
657
658 let result = if self.bypass_evaluation {
662 if target == TypeId::NEVER {
663 SubtypeResult::False
664 } else {
665 self.check_subtype_inner(source, target)
666 }
667 } else {
668 let source_eval = self.evaluate_type(source);
669 let target_eval = self.evaluate_type(target);
670
671 if source_eval != source || target_eval != target {
672 self.check_subtype(source_eval, target_eval)
673 } else if target == TypeId::NEVER {
674 SubtypeResult::False
675 } else {
676 self.check_subtype_inner(source, target)
677 }
678 };
679
680 if let Some(dp) = def_entered {
682 self.def_guard.leave(dp);
683 }
684 self.guard.leave(pair);
685
686 if let Some(db) = self.query_db {
688 let key = self.make_cache_key(source, target);
689 match result {
690 SubtypeResult::True => db.insert_subtype_cache(key, true),
691 SubtypeResult::False => db.insert_subtype_cache(key, false),
692 SubtypeResult::CycleDetected | SubtypeResult::DepthExceeded => {}
693 }
694 }
695
696 result
697 }
698
699 fn check_subtype_inner(&mut self, source: TypeId, target: TypeId) -> SubtypeResult {
701 if !self.strict_null_checks && source.is_nullish() {
704 return SubtypeResult::True;
705 }
706
707 if let Some(shape) = self.apparent_primitive_shape_for_type(source) {
720 if let Some(t_shape_id) = object_shape_id(self.interner, target) {
721 let t_shape = self.interner.object_shape(t_shape_id);
722 return self.check_object_subtype(&shape, None, &t_shape);
723 }
724 if let Some(t_shape_id) = object_with_index_shape_id(self.interner, target) {
725 let t_shape = self.interner.object_shape(t_shape_id);
726 return self.check_object_with_index_subtype(&shape, None, &t_shape);
727 }
728 }
729
730 if let Some(source_cond_id) = conditional_type_id(self.interner, source) {
731 if let Some(target_cond_id) = conditional_type_id(self.interner, target) {
732 let source_cond = self.interner.conditional_type(source_cond_id);
733 let target_cond = self.interner.conditional_type(target_cond_id);
734 return self.check_conditional_subtype(source_cond.as_ref(), target_cond.as_ref());
735 }
736
737 let source_cond = self.interner.conditional_type(source_cond_id);
738 return self.conditional_branches_subtype(source_cond.as_ref(), target);
739 }
740
741 if let Some(target_cond_id) = conditional_type_id(self.interner, target) {
742 let target_cond = self.interner.conditional_type(target_cond_id);
743 return self.subtype_of_conditional_target(source, target_cond.as_ref());
744 }
745
746 if let Some(members) = union_list_id(self.interner, source) {
761 let member_list = self.interner.type_list(members);
762 for &member in member_list.iter() {
763 if !self.check_subtype(member, target).is_true() {
764 if let Some(tracer) = &mut self.tracer
766 && !tracer.on_mismatch_dyn(SubtypeFailureReason::NoUnionMemberMatches {
767 source_type: source,
768 target_union_members: vec![target],
769 })
770 {
771 return SubtypeResult::False;
772 }
773 return SubtypeResult::False;
774 }
775 }
776 return SubtypeResult::True;
777 }
778
779 if let Some(members) = union_list_id(self.interner, target) {
780 if keyof_inner_type(self.interner, source).is_some()
781 && self.is_keyof_subtype_of_string_number_symbol_union(members)
782 {
783 return SubtypeResult::True;
784 }
785
786 if source == TypeId::NUMBER {
788 let member_list = self.interner.type_list(members);
789 for &member in member_list.iter() {
790 let def_id = lazy_def_id(self.interner, member)
791 .or_else(|| enum_components(self.interner, member).map(|(d, _)| d));
792 if let Some(def_id) = def_id
793 && self.resolver.is_numeric_enum(def_id)
794 {
795 return SubtypeResult::True;
796 }
797 }
798 }
799
800 let member_list = self.interner.type_list(members);
801
802 for &member in member_list.iter() {
806 if source == member {
807 return SubtypeResult::True;
808 }
809 }
810
811 for &member in member_list.iter() {
812 if self.check_subtype(source, member).is_true() {
813 return SubtypeResult::True;
814 }
815 }
816
817 if let Some(s_info) = type_param_info(self.interner, source)
821 && let Some(constraint) = s_info.constraint
822 && self.check_subtype(constraint, target).is_true()
823 {
824 return SubtypeResult::True;
825 }
826
827 let s_arc;
830 let source_members: &[TypeId] =
831 if let Some(s_list) = intersection_list_id(self.interner, source) {
832 s_arc = self.interner.type_list(s_list);
833 &s_arc
834 } else {
835 std::slice::from_ref(&source)
836 };
837
838 let mut factored_members = Vec::new();
839 let mut all_contain_source = true;
840 for &member in member_list.iter() {
841 let i_arc;
842 let i_list: &[TypeId] =
843 if let Some(i_members) = intersection_list_id(self.interner, member) {
844 i_arc = self.interner.type_list(i_members);
845 &i_arc
846 } else {
847 std::slice::from_ref(&member)
848 };
849
850 let mut contains_all = true;
851 for &s_m in source_members.iter() {
852 if !i_list.contains(&s_m) {
853 contains_all = false;
854 break;
855 }
856 }
857
858 if contains_all {
863 let mut rem = Vec::new();
864 for &i_m in i_list.iter() {
865 if !source_members.contains(&i_m) {
866 rem.push(i_m);
867 }
868 }
869 factored_members.push(self.interner.intersection(rem));
870 } else {
871 all_contain_source = false;
872 break;
873 }
874 }
875
876 if all_contain_source && !factored_members.is_empty() {
877 let factored_target = self.interner.union(factored_members);
878 if self.check_subtype(source, factored_target).is_true() {
880 return SubtypeResult::True;
881 }
882 }
883
884 if self
889 .type_related_to_discriminated_type(source, &member_list)
890 .is_true()
891 {
892 return SubtypeResult::True;
893 }
894
895 if let Some(s_list) = intersection_list_id(self.interner, source) {
899 let s_member_list = self.interner.type_list(s_list);
900 for &s_member in s_member_list.iter() {
901 if self.check_subtype(s_member, target).is_true() {
902 return SubtypeResult::True;
903 }
904 }
905 }
906
907 if let Some(tracer) = &mut self.tracer
909 && !tracer.on_mismatch_dyn(SubtypeFailureReason::NoUnionMemberMatches {
910 source_type: source,
911 target_union_members: member_list.iter().copied().collect(),
912 })
913 {
914 return SubtypeResult::False;
915 }
916 return SubtypeResult::False;
917 }
918
919 if let Some(members) = intersection_list_id(self.interner, target) {
923 let member_list = self.interner.type_list(members);
924
925 if self.tracer.is_none()
927 && self.can_use_object_intersection_fast_path(&member_list)
928 && let Some(merged_target) = self.build_object_intersection_target(target)
929 {
930 return self.check_subtype(source, merged_target);
931 }
932
933 for &member in member_list.iter() {
934 if !self.check_subtype(source, member).is_true() {
935 return SubtypeResult::False;
936 }
937 }
938 return SubtypeResult::True;
939 }
940
941 if let (Some(s_kind), Some(t_kind)) = (
942 intrinsic_kind(self.interner, source),
943 intrinsic_kind(self.interner, target),
944 ) {
945 return self.check_intrinsic_subtype(s_kind, t_kind);
946 }
947
948 if let Some(s_info) = type_param_info(self.interner, source) {
951 return self.check_type_parameter_subtype(&s_info, target);
952 }
953
954 if let Some(_t_info) = type_param_info(self.interner, target) {
955 if let Some(members) = intersection_list_id(self.interner, source) {
960 let member_list = self.interner.type_list(members);
961 for &member in member_list.iter() {
962 if member == target {
963 return SubtypeResult::True;
964 }
965 }
966 }
967
968 if let Some(tracer) = &mut self.tracer
981 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
982 source_type: source,
983 target_type: target,
984 })
985 {
986 return SubtypeResult::False;
987 }
988 return SubtypeResult::False;
989 }
990
991 if let Some(s_kind) = intrinsic_kind(self.interner, source) {
992 if self.is_boxed_primitive_subtype(s_kind, target) {
993 return SubtypeResult::True;
994 }
995 if s_kind == IntrinsicKind::Object {
999 let target_shape = object_shape_id(self.interner, target)
1000 .or_else(|| object_with_index_shape_id(self.interner, target));
1001 if let Some(t_shape_id) = target_shape {
1002 let t_shape = self.interner.object_shape(t_shape_id);
1003 if t_shape.properties.iter().all(|p| p.optional) {
1004 return SubtypeResult::True;
1005 }
1006 }
1007 }
1008 if let Some(tracer) = &mut self.tracer
1010 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1011 source_type: source,
1012 target_type: target,
1013 })
1014 {
1015 return SubtypeResult::False;
1016 }
1017 return SubtypeResult::False;
1018 }
1019
1020 if let (Some(lit), Some(t_kind)) = (
1021 literal_value(self.interner, source),
1022 intrinsic_kind(self.interner, target),
1023 ) {
1024 return self.check_literal_to_intrinsic(&lit, t_kind);
1025 }
1026
1027 if let (Some(s_lit), Some(t_lit)) = (
1028 literal_value(self.interner, source),
1029 literal_value(self.interner, target),
1030 ) {
1031 if s_lit == t_lit {
1032 return SubtypeResult::True;
1033 }
1034 if let Some(tracer) = &mut self.tracer
1036 && !tracer.on_mismatch_dyn(SubtypeFailureReason::LiteralTypeMismatch {
1037 source_type: source,
1038 target_type: target,
1039 })
1040 {
1041 return SubtypeResult::False;
1042 }
1043 return SubtypeResult::False;
1044 }
1045
1046 if let (Some(LiteralValue::String(s_lit)), Some(t_spans)) = (
1047 literal_value(self.interner, source),
1048 template_literal_id(self.interner, target),
1049 ) {
1050 return self.check_literal_matches_template_literal(s_lit, t_spans);
1051 }
1052
1053 if intrinsic_kind(self.interner, target) == Some(IntrinsicKind::Object) {
1054 if self.is_object_keyword_type(source) {
1055 return SubtypeResult::True;
1056 }
1057 if let Some(tracer) = &mut self.tracer
1059 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1060 source_type: source,
1061 target_type: target,
1062 })
1063 {
1064 return SubtypeResult::False;
1065 }
1066 return SubtypeResult::False;
1067 }
1068
1069 let is_function_target = intrinsic_kind(self.interner, target)
1077 == Some(IntrinsicKind::Function)
1078 || self
1079 .resolver
1080 .is_boxed_type_id(target, IntrinsicKind::Function)
1081 || self
1082 .resolver
1083 .get_boxed_type(IntrinsicKind::Function)
1084 .is_some_and(|boxed| boxed == target)
1085 || lazy_def_id(self.interner, target).is_some_and(|def_id| {
1086 self.resolver
1087 .is_boxed_def_id(def_id, IntrinsicKind::Function)
1088 });
1089 if is_function_target {
1090 if self.is_callable_type(source) {
1091 return SubtypeResult::True;
1092 }
1093 if let Some(tracer) = &mut self.tracer
1095 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1096 source_type: source,
1097 target_type: target,
1098 })
1099 {
1100 return SubtypeResult::False;
1101 }
1102 return SubtypeResult::False;
1103 }
1104
1105 let is_global_object_target = self
1111 .resolver
1112 .is_boxed_type_id(target, IntrinsicKind::Object)
1113 || self
1114 .resolver
1115 .get_boxed_type(IntrinsicKind::Object)
1116 .is_some_and(|boxed| boxed == target)
1117 || lazy_def_id(self.interner, target)
1118 .is_some_and(|t_def| self.resolver.is_boxed_def_id(t_def, IntrinsicKind::Object));
1119 if is_global_object_target {
1120 let source_eval = self.evaluate_type(source);
1121 if self.is_global_object_interface_type(source_eval) {
1122 return SubtypeResult::True;
1123 }
1124
1125 if let Some(tracer) = &mut self.tracer
1126 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1127 source_type: source,
1128 target_type: target,
1129 })
1130 {
1131 return SubtypeResult::False;
1132 }
1133 return SubtypeResult::False;
1134 }
1135
1136 if let (Some(s_elem), Some(t_elem)) = (
1137 array_element_type(self.interner, source),
1138 array_element_type(self.interner, target),
1139 ) {
1140 return self.check_subtype(s_elem, t_elem);
1141 }
1142
1143 if let (Some(s_elems), Some(t_elems)) = (
1144 tuple_list_id(self.interner, source),
1145 tuple_list_id(self.interner, target),
1146 ) {
1147 if self.interner.is_unit_type(source) && self.interner.is_unit_type(target) {
1153 return SubtypeResult::False;
1154 }
1155 let s_elems = self.interner.tuple_list(s_elems);
1156 let t_elems = self.interner.tuple_list(t_elems);
1157 return self.check_tuple_subtype(&s_elems, &t_elems);
1158 }
1159
1160 if let (Some(s_elems), Some(t_elem)) = (
1161 tuple_list_id(self.interner, source),
1162 array_element_type(self.interner, target),
1163 ) {
1164 return self.check_tuple_to_array_subtype(s_elems, t_elem);
1165 }
1166
1167 if let (Some(s_elem), Some(t_elems)) = (
1168 array_element_type(self.interner, source),
1169 tuple_list_id(self.interner, target),
1170 ) {
1171 let t_elems = self.interner.tuple_list(t_elems);
1172 return self.check_array_to_tuple_subtype(s_elem, &t_elems);
1173 }
1174
1175 if let (Some(s_shape_id), Some(t_shape_id)) = (
1176 object_shape_id(self.interner, source),
1177 object_shape_id(self.interner, target),
1178 ) {
1179 let s_shape = self.interner.object_shape(s_shape_id);
1180 let t_shape = self.interner.object_shape(t_shape_id);
1181
1182 if let (Some(s_sym), Some(t_sym)) = (s_shape.symbol, t_shape.symbol)
1190 && s_sym != t_sym
1191 {
1192 let sym_pair = (s_sym, t_sym);
1193 if !self.sym_visiting.insert(sym_pair) {
1194 return SubtypeResult::CycleDetected;
1196 }
1197 let result = self.check_object_subtype(&s_shape, Some(s_shape_id), &t_shape);
1198 self.sym_visiting.remove(&sym_pair);
1199 return result;
1200 }
1201
1202 return self.check_object_subtype(&s_shape, Some(s_shape_id), &t_shape);
1203 }
1204
1205 if let (Some(s_shape_id), Some(t_shape_id)) = (
1206 object_with_index_shape_id(self.interner, source),
1207 object_with_index_shape_id(self.interner, target),
1208 ) {
1209 let s_shape = self.interner.object_shape(s_shape_id);
1210 let t_shape = self.interner.object_shape(t_shape_id);
1211 return self.check_object_with_index_subtype(&s_shape, Some(s_shape_id), &t_shape);
1212 }
1213
1214 if let (Some(s_shape_id), Some(t_shape_id)) = (
1215 object_with_index_shape_id(self.interner, source),
1216 object_shape_id(self.interner, target),
1217 ) {
1218 let s_shape = self.interner.object_shape(s_shape_id);
1219 let t_shape = self.interner.object_shape(t_shape_id);
1220 return self.check_object_with_index_to_object(
1221 &s_shape,
1222 s_shape_id,
1223 &t_shape.properties,
1224 );
1225 }
1226
1227 if let (Some(s_shape_id), Some(t_shape_id)) = (
1228 object_shape_id(self.interner, source),
1229 object_with_index_shape_id(self.interner, target),
1230 ) {
1231 let s_shape = self.interner.object_shape(s_shape_id);
1232 let t_shape = self.interner.object_shape(t_shape_id);
1233 return self.check_object_to_indexed(&s_shape.properties, Some(s_shape_id), &t_shape);
1234 }
1235
1236 if let (Some(s_fn_id), Some(t_fn_id)) = (
1237 function_shape_id(self.interner, source),
1238 function_shape_id(self.interner, target),
1239 ) {
1240 let s_fn = self.interner.function_shape(s_fn_id);
1241 let t_fn = self.interner.function_shape(t_fn_id);
1242 return self.check_function_subtype(&s_fn, &t_fn);
1243 }
1244
1245 let source_function_like = function_shape_id(self.interner, source).is_some()
1251 || callable_shape_id(self.interner, source).is_some_and(|sid| {
1252 let shape = self.interner.callable_shape(sid);
1253 !shape.call_signatures.is_empty()
1254 })
1255 || source == TypeId::FUNCTION;
1256 if source_function_like {
1257 if let Some(t_callable_id) = callable_shape_id(self.interner, target) {
1258 let t_shape = self.interner.callable_shape(t_callable_id);
1259 if t_shape.call_signatures.is_empty() && t_shape.construct_signatures.is_empty() {
1260 let required_props: Vec<_> =
1261 t_shape.properties.iter().filter(|p| !p.optional).collect();
1262 if required_props.len() == 1 {
1263 let name = self.interner.resolve_atom(required_props[0].name);
1264 if name == "call" || name == "apply" {
1265 return SubtypeResult::True;
1266 }
1267 }
1268 }
1269 }
1270 if let Some(t_shape_id) = object_shape_id(self.interner, target)
1271 .or_else(|| object_with_index_shape_id(self.interner, target))
1272 {
1273 let t_shape = self.interner.object_shape(t_shape_id);
1274 let required_props: Vec<_> =
1275 t_shape.properties.iter().filter(|p| !p.optional).collect();
1276 if required_props.len() == 1 {
1277 let name = self.interner.resolve_atom(required_props[0].name);
1278 if name == "call" || name == "apply" {
1279 return SubtypeResult::True;
1280 }
1281 }
1282 }
1283 }
1284
1285 if let (Some(s_callable_id), Some(t_callable_id)) = (
1286 callable_shape_id(self.interner, source),
1287 callable_shape_id(self.interner, target),
1288 ) {
1289 let s_callable = self.interner.callable_shape(s_callable_id);
1290 let t_callable = self.interner.callable_shape(t_callable_id);
1291 return self.check_callable_subtype(&s_callable, &t_callable);
1292 }
1293
1294 if let (Some(s_fn_id), Some(t_callable_id)) = (
1295 function_shape_id(self.interner, source),
1296 callable_shape_id(self.interner, target),
1297 ) {
1298 return self.check_function_to_callable_subtype(s_fn_id, t_callable_id);
1299 }
1300
1301 if let (Some(s_callable_id), Some(t_fn_id)) = (
1302 callable_shape_id(self.interner, source),
1303 function_shape_id(self.interner, target),
1304 ) {
1305 return self.check_callable_to_function_subtype(s_callable_id, t_fn_id);
1306 }
1307
1308 if let (Some(s_app_id), Some(t_app_id)) = (
1309 application_id(self.interner, source),
1310 application_id(self.interner, target),
1311 ) {
1312 return self.check_application_to_application_subtype(s_app_id, t_app_id);
1313 }
1314
1315 if let (Some(s_app_id), Some(t_app_id)) = (
1320 application_id(self.interner, source),
1321 application_id(self.interner, target),
1322 ) {
1323 let result = self.check_application_to_application(source, target, s_app_id, t_app_id);
1324 if result != SubtypeResult::False {
1325 return result;
1326 }
1327 }
1329
1330 if let Some(app_id) = application_id(self.interner, source) {
1331 return self.check_application_expansion_target(source, target, app_id);
1332 }
1333
1334 if let Some(app_id) = application_id(self.interner, target) {
1335 return self.check_source_to_application_expansion(source, target, app_id);
1336 }
1337
1338 if let (Some(source_mapped_id), Some(target_mapped_id)) = (
1340 mapped_type_id(self.interner, source),
1341 mapped_type_id(self.interner, target),
1342 ) {
1343 let result =
1344 self.check_mapped_to_mapped(source, target, source_mapped_id, target_mapped_id);
1345 if result != SubtypeResult::False {
1346 return result;
1347 }
1348 }
1349
1350 if let Some(mapped_id) = mapped_type_id(self.interner, source) {
1351 return self.check_mapped_expansion_target(source, target, mapped_id);
1352 }
1353
1354 if let Some(mapped_id) = mapped_type_id(self.interner, target) {
1355 return self.check_source_to_mapped_expansion(source, target, mapped_id);
1356 }
1357
1358 if let (Some((s_def_id, _s_members)), Some((t_def_id, _t_members))) = (
1368 enum_components(self.interner, source),
1369 enum_components(self.interner, target),
1370 ) {
1371 if s_def_id == t_def_id {
1373 return SubtypeResult::True;
1374 }
1375
1376 if self.resolver.get_enum_parent_def_id(s_def_id) == Some(t_def_id) {
1379 if self.resolver.is_enum_type(target, self.interner) {
1382 return SubtypeResult::True;
1383 }
1384 }
1385
1386 if let Some(tracer) = &mut self.tracer
1389 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1390 source_type: source,
1391 target_type: target,
1392 })
1393 {
1394 return SubtypeResult::False;
1395 }
1396 return SubtypeResult::False;
1397 }
1398
1399 if let Some((_s_def_id, s_members)) = enum_components(self.interner, source) {
1401 return self.check_subtype(s_members, target);
1402 }
1403
1404 if let Some((t_def_id, t_members)) = enum_components(self.interner, target) {
1406 if source == TypeId::NUMBER && self.resolver.is_numeric_enum(t_def_id) {
1408 return SubtypeResult::True;
1409 }
1410 if matches!(
1411 self.interner.lookup(source),
1412 Some(TypeData::Literal(LiteralValue::Number(_)))
1413 ) && self.resolver.is_numeric_enum(t_def_id)
1414 {
1415 return SubtypeResult::True;
1416 }
1417 return self.check_subtype(source, t_members);
1418 }
1419
1420 if let (Some(s_def), Some(t_def)) = (
1429 lazy_def_id(self.interner, source),
1430 lazy_def_id(self.interner, target),
1431 ) {
1432 return self.check_lazy_lazy_subtype(source, target, s_def, t_def);
1434 }
1435
1436 let get_enum_def_id = |type_id: TypeId| -> Option<DefId> {
1445 match self.interner.lookup(type_id) {
1446 Some(TypeData::Enum(def_id, _)) | Some(TypeData::Lazy(def_id)) => Some(def_id),
1447 _ => None,
1448 }
1449 };
1450
1451 if let Some(s_def) = get_enum_def_id(source)
1453 && target == TypeId::NUMBER
1454 && self.resolver.is_numeric_enum(s_def)
1455 {
1456 return SubtypeResult::True;
1457 }
1458
1459 if let Some(t_def) = get_enum_def_id(target) {
1461 if source == TypeId::NUMBER && self.resolver.is_numeric_enum(t_def) {
1462 return SubtypeResult::True;
1463 }
1464 if matches!(
1466 self.interner.lookup(source),
1467 Some(TypeData::Literal(LiteralValue::Number(_)))
1468 ) && self.resolver.is_numeric_enum(t_def)
1469 {
1470 return self.check_subtype(source, self.resolve_lazy_type(target));
1473 }
1474 }
1475
1476 if lazy_def_id(self.interner, source).is_some() {
1477 let resolved = self.resolve_lazy_type(source);
1478 return if resolved != source {
1479 self.check_subtype(resolved, target)
1480 } else {
1481 SubtypeResult::False
1482 };
1483 }
1484
1485 if lazy_def_id(self.interner, target).is_some() {
1486 let resolved = self.resolve_lazy_type(target);
1487 return if resolved != target {
1488 self.check_subtype(source, resolved)
1489 } else {
1490 SubtypeResult::False
1491 };
1492 }
1493
1494 if let (Some(s_sym), Some(t_sym)) = (
1499 ref_symbol(self.interner, source),
1500 ref_symbol(self.interner, target),
1501 ) {
1502 return self.check_ref_ref_subtype(source, target, s_sym, t_sym);
1503 }
1504
1505 if let Some(s_sym) = ref_symbol(self.interner, source) {
1506 return self.check_ref_subtype(source, target, s_sym);
1507 }
1508
1509 if let Some(t_sym) = ref_symbol(self.interner, target) {
1510 return self.check_to_ref_subtype(source, target, t_sym);
1511 }
1512
1513 if let (Some(s_sym), Some(t_sym)) = (
1514 type_query_symbol(self.interner, source),
1515 type_query_symbol(self.interner, target),
1516 ) {
1517 return self.check_typequery_typequery_subtype(source, target, s_sym, t_sym);
1518 }
1519
1520 if let Some(s_sym) = type_query_symbol(self.interner, source) {
1521 return self.check_typequery_subtype(source, target, s_sym);
1522 }
1523
1524 if let Some(t_sym) = type_query_symbol(self.interner, target) {
1525 return self.check_to_typequery_subtype(source, target, t_sym);
1526 }
1527
1528 if let (Some(s_inner), Some(t_inner)) = (
1529 keyof_inner_type(self.interner, source),
1530 keyof_inner_type(self.interner, target),
1531 ) {
1532 return self.check_subtype(t_inner, s_inner);
1533 }
1534
1535 if let (Some(s_inner), Some(t_inner)) = (
1536 readonly_inner_type(self.interner, source),
1537 readonly_inner_type(self.interner, target),
1538 ) {
1539 return self.check_subtype(s_inner, t_inner);
1540 }
1541
1542 if let Some(t_inner) = readonly_inner_type(self.interner, target)
1547 && readonly_inner_type(self.interner, source).is_none()
1548 {
1549 return self.check_subtype(source, t_inner);
1550 }
1551
1552 if let (Some(s_sym), Some(t_sym)) = (
1556 unique_symbol_ref(self.interner, source),
1557 unique_symbol_ref(self.interner, target),
1558 ) {
1559 return if s_sym == t_sym {
1560 SubtypeResult::True
1561 } else {
1562 SubtypeResult::False
1563 };
1564 }
1565
1566 if unique_symbol_ref(self.interner, source).is_some()
1567 && intrinsic_kind(self.interner, target) == Some(IntrinsicKind::Symbol)
1568 {
1569 return SubtypeResult::True;
1570 }
1571
1572 if is_this_type(self.interner, source) && is_this_type(self.interner, target) {
1573 return SubtypeResult::True;
1574 }
1575
1576 if let (Some(s_spans), Some(t_spans)) = (
1577 template_literal_id(self.interner, source),
1578 template_literal_id(self.interner, target),
1579 ) {
1580 return self.check_template_assignable_to_template(s_spans, t_spans);
1581 }
1582
1583 if template_literal_id(self.interner, source).is_some()
1584 && intrinsic_kind(self.interner, target) == Some(IntrinsicKind::String)
1585 {
1586 return SubtypeResult::True;
1587 }
1588
1589 let source_is_callable = function_shape_id(self.interner, source).is_some()
1590 || callable_shape_id(self.interner, source).is_some();
1591 if source_is_callable {
1592 let source_props = if let Some(callable_id) = callable_shape_id(self.interner, source) {
1595 let callable = self.interner.callable_shape(callable_id);
1596 let mut props = callable.properties.clone();
1597 props.sort_by_key(|a| a.name);
1598 Some(ObjectShape {
1599 flags: ObjectFlags::empty(),
1600 properties: props,
1601 string_index: callable.string_index.clone(),
1602 number_index: callable.number_index.clone(),
1603 symbol: callable.symbol,
1604 })
1605 } else {
1606 None
1607 };
1608
1609 if let Some(t_shape_id) = object_shape_id(self.interner, target) {
1610 let t_shape = self.interner.object_shape(t_shape_id);
1611 if t_shape.properties.is_empty() {
1612 return SubtypeResult::True;
1613 }
1614 if let Some(ref s_shape) = source_props {
1616 return self.check_object_subtype(s_shape, None, &t_shape);
1617 }
1618 if let Some(tracer) = &mut self.tracer
1620 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1621 source_type: source,
1622 target_type: target,
1623 })
1624 {
1625 return SubtypeResult::False;
1626 }
1627 return SubtypeResult::False;
1628 }
1629 if let Some(t_shape_id) = object_with_index_shape_id(self.interner, target) {
1630 let t_shape = self.interner.object_shape(t_shape_id);
1631 if t_shape.properties.is_empty() {
1632 return SubtypeResult::True;
1633 }
1634 if let Some(ref s_shape) = source_props {
1636 return self.check_object_subtype(s_shape, None, &t_shape);
1637 }
1638 if let Some(tracer) = &mut self.tracer
1640 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1641 source_type: source,
1642 target_type: target,
1643 })
1644 {
1645 return SubtypeResult::False;
1646 }
1647 return SubtypeResult::False;
1648 }
1649 }
1650
1651 let source_is_array_or_tuple = array_element_type(self.interner, source).is_some()
1652 || tuple_list_id(self.interner, source).is_some();
1653 if source_is_array_or_tuple {
1654 if let Some(t_shape_id) = object_shape_id(self.interner, target) {
1655 let t_shape = self.interner.object_shape(t_shape_id);
1656 if t_shape.properties.is_empty() {
1657 return SubtypeResult::True;
1658 }
1659 let only_length = t_shape
1662 .properties
1663 .iter()
1664 .all(|p| self.interner.resolve_atom(p.name) == "length");
1665 if only_length {
1666 let all_ok = t_shape
1667 .properties
1668 .iter()
1669 .all(|p| self.check_subtype(TypeId::NUMBER, p.type_id).is_true());
1670 if all_ok {
1671 return SubtypeResult::True;
1672 }
1673 }
1674 if let Some(elem) = array_element_type(self.interner, source)
1677 && let Some(result) = self.check_array_interface_subtype(elem, target)
1678 {
1679 return result;
1680 }
1681 if let Some(tracer) = &mut self.tracer
1683 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1684 source_type: source,
1685 target_type: target,
1686 })
1687 {
1688 return SubtypeResult::False;
1689 }
1690 return SubtypeResult::False;
1691 }
1692 if let Some(t_shape_id) = object_with_index_shape_id(self.interner, target) {
1693 let t_shape = self.interner.object_shape(t_shape_id);
1694 if t_shape.properties.is_empty() {
1695 if let Some(ref num_idx) = t_shape.number_index {
1696 let elem_type =
1697 array_element_type(self.interner, source).unwrap_or(TypeId::ANY);
1698 if !self.check_subtype(elem_type, num_idx.value_type).is_true() {
1699 if let Some(tracer) = &mut self.tracer
1701 && !tracer.on_mismatch_dyn(
1702 SubtypeFailureReason::IndexSignatureMismatch {
1703 index_kind: "number",
1704 source_value_type: elem_type,
1705 target_value_type: num_idx.value_type,
1706 },
1707 )
1708 {
1709 return SubtypeResult::False;
1710 }
1711 return SubtypeResult::False;
1712 }
1713 }
1714 return SubtypeResult::True;
1715 }
1716 if let Some(elem) = array_element_type(self.interner, source)
1719 && let Some(result) = self.check_array_interface_subtype(elem, target)
1720 {
1721 return result;
1722 }
1723 if let Some(tracer) = &mut self.tracer
1725 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1726 source_type: source,
1727 target_type: target,
1728 })
1729 {
1730 return SubtypeResult::False;
1731 }
1732 return SubtypeResult::False;
1733 }
1734 }
1735
1736 let interner = self.interner;
1748
1749 let mut visitor = SubtypeVisitor {
1751 checker: self,
1752 source,
1753 target,
1754 };
1755
1756 let result = visitor.visit_type(interner, source);
1758
1759 if result == SubtypeResult::False && self.check_generic_index_access_subtype(source, target)
1760 {
1761 return SubtypeResult::True;
1762 }
1763
1764 if result == SubtypeResult::False
1766 && let Some(tracer) = &mut self.tracer
1767 && !tracer.on_mismatch_dyn(SubtypeFailureReason::TypeMismatch {
1768 source_type: source,
1769 target_type: target,
1770 })
1771 {
1772 return SubtypeResult::False;
1773 }
1774
1775 result
1776 }
1777
1778 fn is_keyof_subtype_of_string_number_symbol_union(&self, members: TypeListId) -> bool {
1783 let member_list = self.interner.type_list(members);
1784 let mut has_string = false;
1786 let mut has_number = false;
1787 let mut has_symbol = false;
1788 for &member in member_list.iter() {
1789 if member == TypeId::STRING {
1790 has_string = true;
1791 } else if member == TypeId::NUMBER {
1792 has_number = true;
1793 } else if member == TypeId::SYMBOL {
1794 has_symbol = true;
1795 }
1796 }
1797 has_string && has_number && has_symbol
1798 }
1799}
1800
1801pub fn is_subtype_of(interner: &dyn TypeDatabase, source: TypeId, target: TypeId) -> bool {
1803 let mut checker = SubtypeChecker::new(interner);
1804 checker.is_subtype_of(source, target)
1805}
1806
1807impl<'a, R: TypeResolver> AssignabilityChecker for SubtypeChecker<'a, R> {
1808 fn is_assignable_to(&mut self, source: TypeId, target: TypeId) -> bool {
1809 SubtypeChecker::is_assignable_to(self, source, target)
1810 }
1811
1812 fn is_assignable_to_bivariant_callback(&mut self, source: TypeId, target: TypeId) -> bool {
1813 let prev_strict = self.strict_function_types;
1814 let prev_param_count = self.allow_bivariant_param_count;
1815 self.strict_function_types = false;
1816 self.allow_bivariant_param_count = true;
1817 let result = SubtypeChecker::is_assignable_to(self, source, target);
1818 self.allow_bivariant_param_count = prev_param_count;
1819 self.strict_function_types = prev_strict;
1820 result
1821 }
1822
1823 fn evaluate_type(&mut self, type_id: TypeId) -> TypeId {
1824 SubtypeChecker::evaluate_type(self, type_id)
1825 }
1826}
1827
1828pub fn are_types_structurally_identical<R: TypeResolver>(
1833 interner: &dyn TypeDatabase,
1834 resolver: &R,
1835 a: TypeId,
1836 b: TypeId,
1837) -> bool {
1838 if a == b {
1839 return true;
1840 }
1841 let mut canonicalizer = crate::canonicalize::Canonicalizer::new(interner, resolver);
1842 let canon_a = canonicalizer.canonicalize(a);
1843 let canon_b = canonicalizer.canonicalize(b);
1844
1845 canon_a == canon_b
1847}
1848
1849pub fn is_subtype_of_with_db(db: &dyn QueryDatabase, source: TypeId, target: TypeId) -> bool {
1852 let mut checker = SubtypeChecker::new(db.as_type_database()).with_query_db(db);
1853 checker.is_subtype_of(source, target)
1854}
1855
1856pub fn is_subtype_of_with_flags(
1859 interner: &dyn TypeDatabase,
1860 source: TypeId,
1861 target: TypeId,
1862 flags: u16,
1863) -> bool {
1864 let mut checker = SubtypeChecker::new(interner).apply_flags(flags);
1865 checker.is_subtype_of(source, target)
1866}
1867
1868#[cfg(test)]
1870#[path = "../tests/subtype_tests.rs"]
1871mod tests;
1872
1873#[cfg(test)]
1874#[path = "../tests/index_signature_tests.rs"]
1875mod index_signature_tests;
1876
1877#[cfg(test)]
1878#[path = "../tests/generics_rules_tests.rs"]
1879mod generics_rules_tests;
1880
1881#[cfg(test)]
1882#[path = "../tests/callable_tests.rs"]
1883mod callable_tests;
1884
1885#[cfg(test)]
1886#[path = "../tests/union_tests.rs"]
1887mod union_tests;
1888
1889#[cfg(test)]
1890#[path = "../tests/typescript_quirks_tests.rs"]
1891mod typescript_quirks_tests;
1892
1893#[cfg(test)]
1894#[path = "../tests/type_predicate_tests.rs"]
1895mod type_predicate_tests;
1896
1897#[cfg(test)]
1898#[path = "../tests/overlap_tests.rs"]
1899mod overlap_tests;