1use crate::diagnostics::SubtypeFailureReason;
8use crate::instantiation::instantiate::{TypeSubstitution, instantiate_type};
9use crate::relations::subtype::SubtypeChecker;
10use crate::type_resolver::TypeResolver;
11use crate::types::{
12 FunctionShape, IntrinsicKind, LiteralValue, ObjectShape, ObjectShapeId, PropertyInfo,
13 TupleElement, TypeId, Visibility,
14};
15use crate::utils;
16use crate::visitor::{
17 array_element_type, callable_shape_id, function_shape_id, intrinsic_kind, literal_value,
18 object_shape_id, object_with_index_shape_id, tuple_list_id, union_list_id,
19};
20
21impl<'a, R: TypeResolver> SubtypeChecker<'a, R> {
22 pub fn explain_failure(
31 &mut self,
32 source: TypeId,
33 target: TypeId,
34 ) -> Option<SubtypeFailureReason> {
35 let pair = (source, target);
36 match self.guard.enter(pair) {
37 crate::recursion::RecursionResult::Entered => {}
38 crate::recursion::RecursionResult::Cycle
39 | crate::recursion::RecursionResult::DepthExceeded
40 | crate::recursion::RecursionResult::IterationExceeded => {
41 return Some(SubtypeFailureReason::TypeMismatch {
42 source_type: source,
43 target_type: target,
44 });
45 }
46 }
47 let result = self.explain_failure_guarded(source, target);
48 self.guard.leave(pair);
49 result
50 }
51
52 fn explain_failure_guarded(
53 &mut self,
54 source: TypeId,
55 target: TypeId,
56 ) -> Option<SubtypeFailureReason> {
57 if source == target {
59 return None;
60 }
61
62 if !self.strict_null_checks && source.is_nullish() {
63 return None;
64 }
65
66 if source.is_any() || target.is_any_or_unknown() {
68 return None;
69 }
70 if source.is_never() {
71 return None;
72 }
73 if source.is_error() || target.is_error() {
75 return Some(SubtypeFailureReason::ErrorType {
76 source_type: source,
77 target_type: target,
78 });
79 }
80
81 self.explain_failure_inner(source, target)
85 }
86
87 fn explain_failure_inner(
88 &mut self,
89 source: TypeId,
90 target: TypeId,
91 ) -> Option<SubtypeFailureReason> {
92 let mut resolved_source = self.resolve_ref_type(source);
96 let mut resolved_target = self.resolve_ref_type(target);
97
98 if let Some(app_id) = crate::visitor::application_id(self.interner, resolved_source)
100 && let Some(expanded) = self.try_expand_application(app_id)
101 {
102 resolved_source = self.resolve_ref_type(expanded);
103 }
104 if let Some(app_id) = crate::visitor::application_id(self.interner, resolved_target)
105 && let Some(expanded) = self.try_expand_application(app_id)
106 {
107 resolved_target = self.resolve_ref_type(expanded);
108 }
109
110 if let Some(shape) = self.apparent_primitive_shape_for_type(resolved_source) {
111 if let Some(t_shape_id) = object_shape_id(self.interner, resolved_target) {
112 let t_shape = self.interner.object_shape(t_shape_id);
113 return self.explain_object_failure(
114 source,
115 target,
116 &shape.properties,
117 None,
118 &t_shape.properties,
119 );
120 }
121 if let Some(t_shape_id) = object_with_index_shape_id(self.interner, resolved_target) {
122 let t_shape = self.interner.object_shape(t_shape_id);
123 return self.explain_indexed_object_failure(source, target, &shape, None, &t_shape);
124 }
125 }
126
127 if let (Some(s_shape_id), Some(t_shape_id)) = (
128 object_shape_id(self.interner, resolved_source),
129 object_shape_id(self.interner, resolved_target),
130 ) {
131 let s_shape = self.interner.object_shape(s_shape_id);
132 let t_shape = self.interner.object_shape(t_shape_id);
133 return self.explain_object_failure(
134 source,
135 target,
136 &s_shape.properties,
137 Some(s_shape_id),
138 &t_shape.properties,
139 );
140 }
141
142 if let (Some(s_shape_id), Some(t_shape_id)) = (
143 object_with_index_shape_id(self.interner, resolved_source),
144 object_with_index_shape_id(self.interner, resolved_target),
145 ) {
146 let s_shape = self.interner.object_shape(s_shape_id);
147 let t_shape = self.interner.object_shape(t_shape_id);
148 return self.explain_indexed_object_failure(
149 source,
150 target,
151 &s_shape,
152 Some(s_shape_id),
153 &t_shape,
154 );
155 }
156
157 if let (Some(s_shape_id), Some(t_shape_id)) = (
158 object_with_index_shape_id(self.interner, resolved_source),
159 object_shape_id(self.interner, resolved_target),
160 ) {
161 let s_shape = self.interner.object_shape(s_shape_id);
162 let t_shape = self.interner.object_shape(t_shape_id);
163 return self.explain_object_with_index_to_object_failure(
164 source,
165 target,
166 &s_shape,
167 s_shape_id,
168 &t_shape.properties,
169 );
170 }
171
172 if let (Some(s_shape_id), Some(t_shape_id)) = (
173 object_shape_id(self.interner, resolved_source),
174 object_with_index_shape_id(self.interner, resolved_target),
175 ) {
176 let s_shape = self.interner.object_shape(s_shape_id);
177 let t_shape = self.interner.object_shape(t_shape_id);
178 if let Some(reason) = self.explain_object_failure(
179 source,
180 target,
181 &s_shape.properties,
182 Some(s_shape_id),
183 &t_shape.properties,
184 ) {
185 return Some(reason);
186 }
187 if let Some(ref number_idx) = t_shape.number_index {
188 return Some(SubtypeFailureReason::IndexSignatureMismatch {
189 index_kind: "number",
190 source_value_type: TypeId::ANY,
191 target_value_type: number_idx.value_type,
192 });
193 }
194 if let Some(ref string_idx) = t_shape.string_index {
195 for prop in &s_shape.properties {
196 let prop_type = self.optional_property_type(prop);
197 if !self
198 .check_subtype(prop_type, string_idx.value_type)
199 .is_true()
200 {
201 return Some(SubtypeFailureReason::IndexSignatureMismatch {
202 index_kind: "string",
203 source_value_type: prop_type,
204 target_value_type: string_idx.value_type,
205 });
206 }
207 }
208 }
209 return None;
210 }
211
212 if let Some(t_elem) = array_element_type(self.interner, resolved_target) {
215 let s_shape_id = object_shape_id(self.interner, resolved_source)
216 .or_else(|| object_with_index_shape_id(self.interner, resolved_source));
217 if let Some(s_sid) = s_shape_id
218 && let Some(array_base) = self.resolver.get_array_base_type()
219 {
220 let params = self.resolver.get_array_base_type_params();
221 let instantiated = if params.is_empty() {
222 array_base
223 } else {
224 let subst = TypeSubstitution::from_args(self.interner, params, &[t_elem]);
225 instantiate_type(self.interner, array_base, &subst)
226 };
227 let resolved_inst = self.resolve_ref_type(instantiated);
228 let s_shape = self.interner.object_shape(s_sid);
231 if let Some(t_obj_sid) = object_shape_id(self.interner, resolved_inst)
232 .or_else(|| object_with_index_shape_id(self.interner, resolved_inst))
233 {
234 let t_shape = self.interner.object_shape(t_obj_sid);
235 return self.explain_object_failure(
236 source,
237 target,
238 &s_shape.properties,
239 Some(s_sid),
240 &t_shape.properties,
241 );
242 }
243 if let Some(callable_sid) = callable_shape_id(self.interner, resolved_inst) {
245 let callable = self.interner.callable_shape(callable_sid);
246 if !callable.properties.is_empty() {
247 return self.explain_object_failure(
248 source,
249 target,
250 &s_shape.properties,
251 Some(s_sid),
252 &callable.properties,
253 );
254 }
255 }
256 }
257 }
258
259 if let Some(s_elem) = array_element_type(self.interner, resolved_source) {
262 let t_shape_id = object_shape_id(self.interner, resolved_target)
263 .or_else(|| object_with_index_shape_id(self.interner, resolved_target));
264 if let Some(t_sid) = t_shape_id
265 && let Some(array_base) = self.resolver.get_array_base_type()
266 {
267 let params = self.resolver.get_array_base_type_params();
268 let instantiated = if params.is_empty() {
269 array_base
270 } else {
271 let subst = TypeSubstitution::from_args(self.interner, params, &[s_elem]);
272 instantiate_type(self.interner, array_base, &subst)
273 };
274 let resolved_inst = self.resolve_ref_type(instantiated);
275 let t_shape = self.interner.object_shape(t_sid);
277 if let Some(s_obj_sid) = object_shape_id(self.interner, resolved_inst)
278 .or_else(|| object_with_index_shape_id(self.interner, resolved_inst))
279 {
280 let s_shape = self.interner.object_shape(s_obj_sid);
281 return self.explain_object_failure(
282 source,
283 target,
284 &s_shape.properties,
285 Some(s_obj_sid),
286 &t_shape.properties,
287 );
288 }
289 if let Some(callable_sid) = callable_shape_id(self.interner, resolved_inst) {
290 let callable = self.interner.callable_shape(callable_sid);
291 if !callable.properties.is_empty() {
292 return self.explain_object_failure(
293 source,
294 target,
295 &callable.properties,
296 None,
297 &t_shape.properties,
298 );
299 }
300 }
301 }
302 }
303
304 if let (Some(s_fn_id), Some(t_fn_id)) = (
305 function_shape_id(self.interner, source),
306 function_shape_id(self.interner, target),
307 ) {
308 let s_fn = self.interner.function_shape(s_fn_id);
309 let t_fn = self.interner.function_shape(t_fn_id);
310 return self.explain_function_failure(&s_fn, &t_fn);
311 }
312
313 if let (Some(s_elem), Some(t_elem)) = (
314 array_element_type(self.interner, source),
315 array_element_type(self.interner, target),
316 ) {
317 if !self.check_subtype(s_elem, t_elem).is_true() {
318 return Some(SubtypeFailureReason::ArrayElementMismatch {
319 source_element: s_elem,
320 target_element: t_elem,
321 });
322 }
323 return None;
324 }
325
326 if let (Some(s_elems), Some(t_elems)) = (
327 tuple_list_id(self.interner, source),
328 tuple_list_id(self.interner, target),
329 ) {
330 let s_elems = self.interner.tuple_list(s_elems);
331 let t_elems = self.interner.tuple_list(t_elems);
332 return self.explain_tuple_failure(&s_elems, &t_elems);
333 }
334
335 if let Some(members) = union_list_id(self.interner, target) {
336 let members = self.interner.type_list(members);
337 return Some(SubtypeFailureReason::NoUnionMemberMatches {
338 source_type: source,
339 target_union_members: members.as_ref().to_vec(),
340 });
341 }
342
343 if let (Some(s_kind), Some(t_kind)) = (
344 intrinsic_kind(self.interner, source),
345 intrinsic_kind(self.interner, target),
346 ) {
347 if s_kind != t_kind {
348 return Some(SubtypeFailureReason::IntrinsicTypeMismatch {
349 source_type: source,
350 target_type: target,
351 });
352 }
353 return None;
354 }
355
356 if literal_value(self.interner, source).is_some()
357 && literal_value(self.interner, target).is_some()
358 {
359 return Some(SubtypeFailureReason::LiteralTypeMismatch {
360 source_type: source,
361 target_type: target,
362 });
363 }
364
365 if let (Some(lit), Some(t_kind)) = (
366 literal_value(self.interner, source),
367 intrinsic_kind(self.interner, target),
368 ) {
369 let compatible = match lit {
370 LiteralValue::String(_) => t_kind == IntrinsicKind::String,
371 LiteralValue::Number(_) => t_kind == IntrinsicKind::Number,
372 LiteralValue::BigInt(_) => t_kind == IntrinsicKind::Bigint,
373 LiteralValue::Boolean(_) => t_kind == IntrinsicKind::Boolean,
374 };
375 if !compatible {
376 return Some(SubtypeFailureReason::LiteralTypeMismatch {
377 source_type: source,
378 target_type: target,
379 });
380 }
381 return None;
382 }
383
384 if intrinsic_kind(self.interner, source).is_some()
385 && literal_value(self.interner, target).is_some()
386 {
387 return Some(SubtypeFailureReason::TypeMismatch {
388 source_type: source,
389 target_type: target,
390 });
391 }
392
393 Some(SubtypeFailureReason::TypeMismatch {
394 source_type: source,
395 target_type: target,
396 })
397 }
398
399 fn explain_object_failure(
401 &mut self,
402 source: TypeId,
403 target: TypeId,
404 source_props: &[PropertyInfo],
405 source_shape_id: Option<ObjectShapeId>,
406 target_props: &[PropertyInfo],
407 ) -> Option<SubtypeFailureReason> {
408 let mut missing_props: Vec<tsz_common::interner::Atom> = Vec::new();
412 for t_prop in target_props {
413 if !t_prop.optional {
414 let s_prop = self.lookup_property(source_props, source_shape_id, t_prop.name);
415 if s_prop.is_none() {
416 missing_props.push(t_prop.name);
417 }
418 }
419 }
420
421 if missing_props.len() > 1 {
422 return Some(SubtypeFailureReason::MissingProperties {
423 property_names: missing_props,
424 source_type: source,
425 target_type: target,
426 });
427 }
428 if missing_props.len() == 1 {
429 return Some(SubtypeFailureReason::MissingProperty {
430 property_name: missing_props[0],
431 source_type: source,
432 target_type: target,
433 });
434 }
435
436 for t_prop in target_props {
438 let s_prop = self.lookup_property(source_props, source_shape_id, t_prop.name);
439
440 if let Some(sp) = s_prop {
441 if t_prop.visibility != Visibility::Public {
443 if sp.parent_id != t_prop.parent_id {
444 return Some(SubtypeFailureReason::PropertyNominalMismatch {
445 property_name: t_prop.name,
446 });
447 }
448 }
449 else if sp.visibility != Visibility::Public {
451 return Some(SubtypeFailureReason::PropertyVisibilityMismatch {
452 property_name: t_prop.name,
453 source_visibility: sp.visibility,
454 target_visibility: t_prop.visibility,
455 });
456 }
457
458 if sp.optional && !t_prop.optional {
460 return Some(SubtypeFailureReason::OptionalPropertyRequired {
461 property_name: t_prop.name,
462 });
463 }
464
465 let source_type = self.optional_property_type(sp);
467 let target_type = self.optional_property_type(t_prop);
468 let allow_bivariant = sp.is_method || t_prop.is_method;
469 if !self
470 .check_subtype_with_method_variance(source_type, target_type, allow_bivariant)
471 .is_true()
472 {
473 let nested = self.explain_failure_with_method_variance(
474 source_type,
475 target_type,
476 allow_bivariant,
477 );
478 return Some(SubtypeFailureReason::PropertyTypeMismatch {
479 property_name: t_prop.name,
480 source_property_type: source_type,
481 target_property_type: target_type,
482 nested_reason: nested.map(Box::new),
483 });
484 }
485 if !t_prop.readonly
486 && (sp.write_type != sp.type_id || t_prop.write_type != t_prop.type_id)
487 {
488 let source_write = self.optional_property_write_type(sp);
489 let target_write = self.optional_property_write_type(t_prop);
490 if !self
491 .check_subtype_with_method_variance(
492 target_write,
493 source_write,
494 allow_bivariant,
495 )
496 .is_true()
497 {
498 let nested = self.explain_failure_with_method_variance(
499 target_write,
500 source_write,
501 allow_bivariant,
502 );
503 return Some(SubtypeFailureReason::PropertyTypeMismatch {
504 property_name: t_prop.name,
505 source_property_type: source_write,
506 target_property_type: target_write,
507 nested_reason: nested.map(Box::new),
508 });
509 }
510 }
511 }
512 }
513
514 None
515 }
516
517 fn explain_indexed_object_failure(
519 &mut self,
520 source: TypeId,
521 target: TypeId,
522 source_shape: &ObjectShape,
523 source_shape_id: Option<ObjectShapeId>,
524 target_shape: &ObjectShape,
525 ) -> Option<SubtypeFailureReason> {
526 if let Some(reason) = self.explain_object_failure(
528 source,
529 target,
530 &source_shape.properties,
531 source_shape_id,
532 &target_shape.properties,
533 ) {
534 return Some(reason);
535 }
536
537 if let Some(ref t_string_idx) = target_shape.string_index {
539 match &source_shape.string_index {
540 Some(s_string_idx) => {
541 if s_string_idx.readonly && !t_string_idx.readonly {
542 return Some(SubtypeFailureReason::TypeMismatch {
543 source_type: source,
544 target_type: target,
545 });
546 }
547 if !self
548 .check_subtype(s_string_idx.value_type, t_string_idx.value_type)
549 .is_true()
550 {
551 return Some(SubtypeFailureReason::IndexSignatureMismatch {
552 index_kind: "string",
553 source_value_type: s_string_idx.value_type,
554 target_value_type: t_string_idx.value_type,
555 });
556 }
557 }
558 None => {
559 for prop in &source_shape.properties {
560 let prop_type = self.optional_property_type(prop);
561 if !self
562 .check_subtype(prop_type, t_string_idx.value_type)
563 .is_true()
564 {
565 return Some(SubtypeFailureReason::IndexSignatureMismatch {
566 index_kind: "string",
567 source_value_type: prop_type,
568 target_value_type: t_string_idx.value_type,
569 });
570 }
571 }
572 }
573 }
574 }
575
576 if let Some(ref t_number_idx) = target_shape.number_index
578 && let Some(ref s_number_idx) = source_shape.number_index
579 {
580 if s_number_idx.readonly && !t_number_idx.readonly {
581 return Some(SubtypeFailureReason::TypeMismatch {
582 source_type: source,
583 target_type: target,
584 });
585 }
586 if !self
587 .check_subtype(s_number_idx.value_type, t_number_idx.value_type)
588 .is_true()
589 {
590 return Some(SubtypeFailureReason::IndexSignatureMismatch {
591 index_kind: "number",
592 source_value_type: s_number_idx.value_type,
593 target_value_type: t_number_idx.value_type,
594 });
595 }
596 }
597
598 if let Some(reason) =
599 self.explain_properties_against_index_signatures(&source_shape.properties, target_shape)
600 {
601 return Some(reason);
602 }
603
604 None
605 }
606
607 fn explain_object_with_index_to_object_failure(
608 &mut self,
609 source: TypeId,
610 target: TypeId,
611 source_shape: &ObjectShape,
612 source_shape_id: ObjectShapeId,
613 target_props: &[PropertyInfo],
614 ) -> Option<SubtypeFailureReason> {
615 for t_prop in target_props {
616 if let Some(sp) =
617 self.lookup_property(&source_shape.properties, Some(source_shape_id), t_prop.name)
618 {
619 if t_prop.visibility != Visibility::Public {
623 if sp.parent_id != t_prop.parent_id {
624 return Some(SubtypeFailureReason::PropertyNominalMismatch {
625 property_name: t_prop.name,
626 });
627 }
628 }
629 else if sp.visibility != Visibility::Public {
631 return Some(SubtypeFailureReason::PropertyVisibilityMismatch {
632 property_name: t_prop.name,
633 source_visibility: sp.visibility,
634 target_visibility: t_prop.visibility,
635 });
636 }
637
638 if sp.optional && !t_prop.optional {
639 return Some(SubtypeFailureReason::OptionalPropertyRequired {
640 property_name: t_prop.name,
641 });
642 }
643 let source_type = self.optional_property_type(sp);
647 let target_type = self.optional_property_type(t_prop);
648 let allow_bivariant = sp.is_method || t_prop.is_method;
649 if !self
650 .check_subtype_with_method_variance(source_type, target_type, allow_bivariant)
651 .is_true()
652 {
653 let nested = self.explain_failure_with_method_variance(
654 source_type,
655 target_type,
656 allow_bivariant,
657 );
658 return Some(SubtypeFailureReason::PropertyTypeMismatch {
659 property_name: t_prop.name,
660 source_property_type: source_type,
661 target_property_type: target_type,
662 nested_reason: nested.map(Box::new),
663 });
664 }
665 if !t_prop.readonly
666 && (sp.write_type != sp.type_id || t_prop.write_type != t_prop.type_id)
667 {
668 let source_write = self.optional_property_write_type(sp);
669 let target_write = self.optional_property_write_type(t_prop);
670 if !self
671 .check_subtype_with_method_variance(
672 target_write,
673 source_write,
674 allow_bivariant,
675 )
676 .is_true()
677 {
678 let nested = self.explain_failure_with_method_variance(
679 target_write,
680 source_write,
681 allow_bivariant,
682 );
683 return Some(SubtypeFailureReason::PropertyTypeMismatch {
684 property_name: t_prop.name,
685 source_property_type: source_write,
686 target_property_type: target_write,
687 nested_reason: nested.map(Box::new),
688 });
689 }
690 }
691 continue;
692 }
693
694 let mut checked = false;
695 let target_type = self.optional_property_type(t_prop);
696
697 if utils::is_numeric_property_name(self.interner, t_prop.name)
698 && let Some(number_idx) = &source_shape.number_index
699 {
700 checked = true;
701 if number_idx.readonly && !t_prop.readonly {
702 return Some(SubtypeFailureReason::ReadonlyPropertyMismatch {
703 property_name: t_prop.name,
704 });
705 }
706 if !self
707 .check_subtype_with_method_variance(
708 number_idx.value_type,
709 target_type,
710 t_prop.is_method,
711 )
712 .is_true()
713 {
714 return Some(SubtypeFailureReason::IndexSignatureMismatch {
715 index_kind: "number",
716 source_value_type: number_idx.value_type,
717 target_value_type: target_type,
718 });
719 }
720 }
721
722 if let Some(string_idx) = &source_shape.string_index {
723 checked = true;
724 if string_idx.readonly && !t_prop.readonly {
725 return Some(SubtypeFailureReason::ReadonlyPropertyMismatch {
726 property_name: t_prop.name,
727 });
728 }
729 if !self
730 .check_subtype_with_method_variance(
731 string_idx.value_type,
732 target_type,
733 t_prop.is_method,
734 )
735 .is_true()
736 {
737 return Some(SubtypeFailureReason::IndexSignatureMismatch {
738 index_kind: "string",
739 source_value_type: string_idx.value_type,
740 target_value_type: target_type,
741 });
742 }
743 }
744
745 if !checked && !t_prop.optional {
746 return Some(SubtypeFailureReason::MissingProperty {
747 property_name: t_prop.name,
748 source_type: source,
749 target_type: target,
750 });
751 }
752 }
753
754 None
755 }
756
757 fn explain_properties_against_index_signatures(
758 &mut self,
759 source: &[PropertyInfo],
760 target: &ObjectShape,
761 ) -> Option<SubtypeFailureReason> {
762 let string_index = target.string_index.as_ref();
763 let number_index = target.number_index.as_ref();
764
765 if string_index.is_none() && number_index.is_none() {
766 return None;
767 }
768
769 for prop in source {
770 let prop_type = self.optional_property_type(prop);
771 let allow_bivariant = prop.is_method;
772
773 if let Some(number_idx) = number_index {
774 let is_numeric = utils::is_numeric_property_name(self.interner, prop.name);
775 if is_numeric {
776 if !number_idx.readonly && prop.readonly {
777 return Some(SubtypeFailureReason::ReadonlyPropertyMismatch {
778 property_name: prop.name,
779 });
780 }
781 if !self
782 .check_subtype_with_method_variance(
783 prop_type,
784 number_idx.value_type,
785 allow_bivariant,
786 )
787 .is_true()
788 {
789 return Some(SubtypeFailureReason::IndexSignatureMismatch {
790 index_kind: "number",
791 source_value_type: prop_type,
792 target_value_type: number_idx.value_type,
793 });
794 }
795 }
796 }
797
798 if let Some(string_idx) = string_index {
799 if !string_idx.readonly && prop.readonly {
800 return Some(SubtypeFailureReason::ReadonlyPropertyMismatch {
801 property_name: prop.name,
802 });
803 }
804 if !self
805 .check_subtype_with_method_variance(
806 prop_type,
807 string_idx.value_type,
808 allow_bivariant,
809 )
810 .is_true()
811 {
812 return Some(SubtypeFailureReason::IndexSignatureMismatch {
813 index_kind: "string",
814 source_value_type: prop_type,
815 target_value_type: string_idx.value_type,
816 });
817 }
818 }
819 }
820
821 None
822 }
823
824 fn explain_function_failure(
826 &mut self,
827 source: &FunctionShape,
828 target: &FunctionShape,
829 ) -> Option<SubtypeFailureReason> {
830 if !(self
832 .check_subtype(source.return_type, target.return_type)
833 .is_true()
834 || self.allow_void_return && target.return_type == TypeId::VOID)
835 {
836 let nested = self.explain_failure(source.return_type, target.return_type);
837 return Some(SubtypeFailureReason::ReturnTypeMismatch {
838 source_return: source.return_type,
839 target_return: target.return_type,
840 nested_reason: nested.map(Box::new),
841 });
842 }
843
844 let target_has_rest = target.params.last().is_some_and(|p| p.rest);
846 let rest_elem_type = if target_has_rest {
847 target
848 .params
849 .last()
850 .map(|param| self.get_array_element_type(param.type_id))
851 } else {
852 None
853 };
854 let rest_is_top = self.allow_bivariant_rest
855 && matches!(rest_elem_type, Some(TypeId::ANY | TypeId::UNKNOWN));
856 let source_required = self.required_param_count(&source.params);
857 let target_required = self.required_param_count(&target.params);
858 let too_many_params = !self.allow_bivariant_param_count
864 && !rest_is_top
865 && !target_has_rest
866 && source_required > target_required;
867 if !target_has_rest && too_many_params {
868 return Some(SubtypeFailureReason::TooManyParameters {
869 source_count: source_required,
870 target_count: target_required,
871 });
872 }
873
874 let source_has_rest = source.params.last().is_some_and(|p| p.rest);
876 let target_fixed_count = if target_has_rest {
877 target.params.len().saturating_sub(1)
878 } else {
879 target.params.len()
880 };
881 let source_fixed_count = if source_has_rest {
882 source.params.len().saturating_sub(1)
883 } else {
884 source.params.len()
885 };
886 let fixed_compare_count = std::cmp::min(source_fixed_count, target_fixed_count);
887 let is_method_or_ctor =
889 source.is_method || target.is_method || source.is_constructor || target.is_constructor;
890 for i in 0..fixed_compare_count {
891 let s_param = &source.params[i];
892 let t_param = &target.params[i];
893 if !self.are_parameters_compatible_impl(
895 s_param.type_id,
896 t_param.type_id,
897 is_method_or_ctor,
898 ) {
899 return Some(SubtypeFailureReason::ParameterTypeMismatch {
900 param_index: i,
901 source_param: s_param.type_id,
902 target_param: t_param.type_id,
903 });
904 }
905 }
906
907 if target_has_rest {
908 let Some(rest_elem_type) = rest_elem_type else {
909 return None; };
911 if rest_is_top {
912 return None;
913 }
914
915 for i in target_fixed_count..source_fixed_count {
916 let s_param = &source.params[i];
917 if !self.are_parameters_compatible_impl(
918 s_param.type_id,
919 rest_elem_type,
920 is_method_or_ctor,
921 ) {
922 return Some(SubtypeFailureReason::ParameterTypeMismatch {
923 param_index: i,
924 source_param: s_param.type_id,
925 target_param: rest_elem_type,
926 });
927 }
928 }
929
930 if source_has_rest {
931 let s_rest_param = source.params.last()?;
932 let s_rest_elem = self.get_array_element_type(s_rest_param.type_id);
933 if !self.are_parameters_compatible_impl(
934 s_rest_elem,
935 rest_elem_type,
936 is_method_or_ctor,
937 ) {
938 return Some(SubtypeFailureReason::ParameterTypeMismatch {
939 param_index: source_fixed_count,
940 source_param: s_rest_elem,
941 target_param: rest_elem_type,
942 });
943 }
944 }
945 }
946
947 if source_has_rest {
948 let rest_param = source.params.last()?;
949 let rest_elem_type = self.get_array_element_type(rest_param.type_id);
950 let rest_is_top = self.allow_bivariant_rest && rest_elem_type.is_any_or_unknown();
951
952 if !rest_is_top {
953 for i in source_fixed_count..target_fixed_count {
954 let t_param = &target.params[i];
955 if !self.are_parameters_compatible(rest_elem_type, t_param.type_id) {
956 return Some(SubtypeFailureReason::ParameterTypeMismatch {
957 param_index: i,
958 source_param: rest_elem_type,
959 target_param: t_param.type_id,
960 });
961 }
962 }
963 }
964 }
965
966 None
967 }
968
969 fn explain_tuple_failure(
971 &mut self,
972 source: &[TupleElement],
973 target: &[TupleElement],
974 ) -> Option<SubtypeFailureReason> {
975 let source_required = source.iter().filter(|e| !e.optional && !e.rest).count();
976 let target_required = target.iter().filter(|e| !e.optional && !e.rest).count();
977
978 if source_required < target_required {
979 return Some(SubtypeFailureReason::TupleElementMismatch {
980 source_count: source.len(),
981 target_count: target.len(),
982 });
983 }
984
985 for (i, t_elem) in target.iter().enumerate() {
986 if t_elem.rest {
987 let expansion = self.expand_tuple_rest(t_elem.type_id);
988 let outer_tail = &target[i + 1..];
989 let combined_suffix: Vec<_> = expansion
991 .tail
992 .iter()
993 .chain(outer_tail.iter())
994 .cloned()
995 .collect();
996
997 let mut source_end = source.len();
998 for tail_elem in combined_suffix.iter().rev() {
999 if source_end <= i {
1000 if !tail_elem.optional {
1001 return Some(SubtypeFailureReason::TupleElementMismatch {
1002 source_count: source.len(),
1003 target_count: target.len(),
1004 });
1005 }
1006 break;
1007 }
1008 let s_elem = &source[source_end - 1];
1009 if s_elem.rest {
1010 if !tail_elem.optional {
1011 return Some(SubtypeFailureReason::TupleElementMismatch {
1012 source_count: source.len(),
1013 target_count: target.len(),
1014 });
1015 }
1016 break;
1017 }
1018 let assignable = self
1019 .check_subtype(s_elem.type_id, tail_elem.type_id)
1020 .is_true();
1021 if tail_elem.optional && !assignable {
1022 break;
1023 }
1024 if !assignable {
1025 return Some(SubtypeFailureReason::TupleElementTypeMismatch {
1026 index: source_end - 1,
1027 source_element: s_elem.type_id,
1028 target_element: tail_elem.type_id,
1029 });
1030 }
1031 source_end -= 1;
1032 }
1033
1034 let mut source_iter = source.iter().enumerate().take(source_end).skip(i);
1035
1036 for t_fixed in &expansion.fixed {
1037 match source_iter.next() {
1038 Some((j, s_elem)) => {
1039 if s_elem.rest {
1040 return Some(SubtypeFailureReason::TupleElementMismatch {
1041 source_count: source.len(),
1042 target_count: target.len(),
1043 });
1044 }
1045 if !self
1046 .check_subtype(s_elem.type_id, t_fixed.type_id)
1047 .is_true()
1048 {
1049 return Some(SubtypeFailureReason::TupleElementTypeMismatch {
1050 index: j,
1051 source_element: s_elem.type_id,
1052 target_element: t_fixed.type_id,
1053 });
1054 }
1055 }
1056 None => {
1057 if !t_fixed.optional {
1058 return Some(SubtypeFailureReason::TupleElementMismatch {
1059 source_count: source.len(),
1060 target_count: target.len(),
1061 });
1062 }
1063 }
1064 }
1065 }
1066
1067 if let Some(variadic) = expansion.variadic {
1068 let variadic_array = self.interner.array(variadic);
1069 for (j, s_elem) in source_iter {
1070 let target_type = if s_elem.rest {
1071 variadic_array
1072 } else {
1073 variadic
1074 };
1075 if !self.check_subtype(s_elem.type_id, target_type).is_true() {
1076 return Some(SubtypeFailureReason::TupleElementTypeMismatch {
1077 index: j,
1078 source_element: s_elem.type_id,
1079 target_element: target_type,
1080 });
1081 }
1082 }
1083 return None;
1084 }
1085
1086 if source_iter.next().is_some() {
1087 return Some(SubtypeFailureReason::TupleElementMismatch {
1088 source_count: source.len(),
1089 target_count: target.len(),
1090 });
1091 }
1092 return None;
1093 }
1094
1095 if let Some(s_elem) = source.get(i) {
1096 if s_elem.rest {
1097 return Some(SubtypeFailureReason::TupleElementMismatch {
1099 source_count: source.len(), target_count: target.len(),
1101 });
1102 }
1103
1104 if !self.check_subtype(s_elem.type_id, t_elem.type_id).is_true() {
1105 return Some(SubtypeFailureReason::TupleElementTypeMismatch {
1106 index: i,
1107 source_element: s_elem.type_id,
1108 target_element: t_elem.type_id,
1109 });
1110 }
1111 } else if !t_elem.optional {
1112 return Some(SubtypeFailureReason::TupleElementMismatch {
1113 source_count: source.len(),
1114 target_count: target.len(),
1115 });
1116 }
1117 }
1118
1119 if source.len() > target.len() {
1121 return Some(SubtypeFailureReason::TupleElementMismatch {
1122 source_count: source.len(),
1123 target_count: target.len(),
1124 });
1125 }
1126
1127 for s_elem in source {
1128 if s_elem.rest {
1129 return Some(SubtypeFailureReason::TupleElementMismatch {
1130 source_count: source.len(), target_count: target.len(),
1132 });
1133 }
1134 }
1135
1136 None
1137 }
1138
1139 pub fn are_types_structurally_identical(&self, a: TypeId, b: TypeId) -> bool {
1144 if a == b {
1145 return true;
1146 }
1147
1148 if let Some(db) = self.query_db {
1150 return db.canonical_id(a) == db.canonical_id(b);
1151 }
1152
1153 let mut canonicalizer =
1155 crate::canonicalize::Canonicalizer::new(self.interner, self.resolver);
1156 let canon_a = canonicalizer.canonicalize(a);
1157 let canon_b = canonicalizer.canonicalize(b);
1158
1159 canon_a == canon_b
1161 }
1162}