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