1pub use crate::binary_ops::{BinaryOpEvaluator, BinaryOpResult, PrimitiveClass};
29
30use crate::diagnostics::PendingDiagnostic;
31use crate::instantiate::{TypeSubstitution, instantiate_type};
32#[cfg(test)]
33use crate::types::*;
34use crate::types::{
35 CallSignature, CallableShape, CallableShapeId, FunctionShape, FunctionShapeId, IntrinsicKind,
36 LiteralValue, ParamInfo, TemplateSpan, TupleElement, TypeData, TypeId, TypeListId,
37 TypePredicate,
38};
39use crate::visitor::TypeVisitor;
40use crate::{QueryDatabase, TypeDatabase};
41use rustc_hash::{FxHashMap, FxHashSet};
42use std::cell::RefCell;
43use tracing::{debug, trace};
44
45pub const MAX_CONSTRAINT_RECURSION_DEPTH: usize = 100;
47
48pub trait AssignabilityChecker {
49 fn is_assignable_to(&mut self, source: TypeId, target: TypeId) -> bool;
50
51 fn is_assignable_to_strict(&mut self, source: TypeId, target: TypeId) -> bool {
52 self.is_assignable_to(source, target)
53 }
54
55 fn is_assignable_to_bivariant_callback(&mut self, source: TypeId, target: TypeId) -> bool {
60 self.is_assignable_to(source, target)
61 }
62
63 fn evaluate_type(&mut self, type_id: TypeId) -> TypeId {
68 type_id
69 }
70}
71
72#[derive(Clone, Debug)]
78pub enum CallResult {
79 Success(TypeId),
81
82 NotCallable { type_id: TypeId },
84
85 ThisTypeMismatch {
87 expected_this: TypeId,
88 actual_this: TypeId,
89 },
90
91 ArgumentCountMismatch {
93 expected_min: usize,
94 expected_max: Option<usize>,
95 actual: usize,
96 },
97
98 OverloadArgumentCountMismatch {
101 actual: usize,
102 expected_low: usize,
103 expected_high: usize,
104 },
105
106 ArgumentTypeMismatch {
108 index: usize,
109 expected: TypeId,
110 actual: TypeId,
111 },
112
113 NonVoidFunctionCalledWithNew,
115
116 TypeParameterConstraintViolation {
121 inferred_type: TypeId,
123 constraint_type: TypeId,
125 return_type: TypeId,
127 },
128
129 NoOverloadMatch {
131 func_type: TypeId,
132 arg_types: Vec<TypeId>,
133 failures: Vec<PendingDiagnostic>,
134 fallback_return: TypeId,
135 },
136}
137
138struct TupleRestExpansion {
139 fixed: Vec<TupleElement>,
141 variadic: Option<TypeId>,
143 tail: Vec<TupleElement>,
145}
146
147pub struct CallEvaluator<'a, C: AssignabilityChecker> {
149 pub(crate) interner: &'a dyn QueryDatabase,
150 pub(crate) checker: &'a mut C,
151 pub(crate) defaulted_placeholders: FxHashSet<TypeId>,
152 force_bivariant_callbacks: bool,
153 pub(crate) contextual_type: Option<TypeId>,
156 pub(crate) actual_this_type: Option<TypeId>,
158 pub(crate) constraint_recursion_depth: RefCell<usize>,
160 pub(crate) constraint_pairs: RefCell<FxHashSet<(TypeId, TypeId)>>,
162 pub last_instantiated_predicate: Option<(TypePredicate, Vec<ParamInfo>)>,
165}
166
167impl<'a, C: AssignabilityChecker> CallEvaluator<'a, C> {
168 pub fn new(interner: &'a dyn QueryDatabase, checker: &'a mut C) -> Self {
169 CallEvaluator {
170 interner,
171 checker,
172 defaulted_placeholders: FxHashSet::default(),
173 force_bivariant_callbacks: false,
174 contextual_type: None,
175 actual_this_type: None,
176 constraint_recursion_depth: RefCell::new(0),
177 constraint_pairs: RefCell::new(FxHashSet::default()),
178 last_instantiated_predicate: None,
179 }
180 }
181
182 pub const fn set_actual_this_type(&mut self, type_id: Option<TypeId>) {
184 self.actual_this_type = type_id;
185 }
186
187 pub const fn set_contextual_type(&mut self, ctx_type: Option<TypeId>) {
192 self.contextual_type = ctx_type;
193 }
194
195 pub const fn set_force_bivariant_callbacks(&mut self, enabled: bool) {
196 self.force_bivariant_callbacks = enabled;
197 }
198
199 pub(crate) fn is_function_union_compat(
200 &mut self,
201 arg_type: TypeId,
202 mut target_type: TypeId,
203 ) -> bool {
204 if let Some(TypeData::Lazy(def_id)) = self.interner.lookup(target_type)
205 && let Some(resolved) = self.interner.resolve_lazy(def_id, self.interner)
206 {
207 target_type = resolved;
208 debug!(
209 target_type = target_type.0,
210 target_key = ?self.interner.lookup(target_type),
211 "is_function_union_compat: resolved lazy target"
212 );
213 }
214 if !matches!(self.interner.lookup(target_type), Some(TypeData::Union(_))) {
215 let evaluated = self.interner.evaluate_type(target_type);
216 if evaluated != target_type {
217 target_type = evaluated;
218 debug!(
219 target_type = target_type.0,
220 target_key = ?self.interner.lookup(target_type),
221 "is_function_union_compat: evaluated target"
222 );
223 }
224 if let Some(TypeData::Lazy(def_id)) = self.interner.lookup(target_type)
225 && let Some(resolved) = self.interner.resolve_lazy(def_id, self.interner)
226 {
227 target_type = resolved;
228 debug!(
229 target_type = target_type.0,
230 target_key = ?self.interner.lookup(target_type),
231 "is_function_union_compat: resolved lazy target after eval"
232 );
233 }
234 }
235 let Some(TypeData::Union(members_id)) = self.interner.lookup(target_type) else {
236 return false;
237 };
238 if !crate::type_queries::is_callable_type(self.interner, arg_type) {
239 return false;
240 }
241 let members = self.interner.type_list(members_id);
242 if members
243 .iter()
244 .any(|&member| self.checker.is_assignable_to(arg_type, member))
245 {
246 return true;
247 }
248 let synthetic_any_fn = self.interner.function(FunctionShape {
249 type_params: vec![],
250 params: vec![],
251 return_type: TypeId::ANY,
252 this_type: None,
253 type_predicate: None,
254 is_constructor: false,
255 is_method: false,
256 });
257 if members
258 .iter()
259 .any(|&member| self.checker.is_assignable_to(synthetic_any_fn, member))
260 {
261 return true;
262 }
263 members
264 .iter()
265 .any(|&member| self.is_function_like_union_member(member))
266 }
267
268 fn normalize_union_member(&self, mut member: TypeId) -> TypeId {
269 for _ in 0..8 {
270 let next = match self.interner.lookup(member) {
271 Some(TypeData::Lazy(def_id)) => self
272 .interner
273 .resolve_lazy(def_id, self.interner)
274 .unwrap_or(member),
275 Some(TypeData::Application(_) | TypeData::Mapped(_)) => {
276 self.interner.evaluate_type(member)
277 }
278 _ => member,
279 };
280 if next == member {
281 break;
282 }
283 member = next;
284 }
285 member
286 }
287
288 fn is_function_like_union_member(&self, member: TypeId) -> bool {
289 let member = self.normalize_union_member(member);
290 match self.interner.lookup(member) {
291 Some(TypeData::Intrinsic(IntrinsicKind::Function))
292 | Some(TypeData::Function(_) | TypeData::Callable(_)) => true,
293 Some(TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id)) => {
294 let shape = self.interner.object_shape(shape_id);
295 let apply = self.interner.intern_string("apply");
296 let call = self.interner.intern_string("call");
297 let has_apply = shape.properties.iter().any(|prop| prop.name == apply);
298 let has_call = shape.properties.iter().any(|prop| prop.name == call);
299 has_apply && has_call
300 }
301 Some(TypeData::Union(members_id)) => self
302 .interner
303 .type_list(members_id)
304 .iter()
305 .any(|&m| self.is_function_like_union_member(m)),
306 Some(TypeData::Intersection(members_id)) => self
307 .interner
308 .type_list(members_id)
309 .iter()
310 .any(|&m| self.is_function_like_union_member(m)),
311 _ => false,
312 }
313 }
314
315 pub fn infer_call_signature(&mut self, sig: &CallSignature, arg_types: &[TypeId]) -> TypeId {
316 let func = FunctionShape {
317 params: sig.params.clone(),
318 this_type: sig.this_type,
319 return_type: sig.return_type,
320 type_params: sig.type_params.clone(),
321 type_predicate: sig.type_predicate.clone(),
322 is_constructor: false,
323 is_method: sig.is_method,
324 };
325 match self.resolve_function_call(&func, arg_types) {
326 CallResult::Success(ret) => ret,
327 _ => TypeId::ERROR,
329 }
330 }
331
332 pub fn infer_generic_function(&mut self, func: &FunctionShape, arg_types: &[TypeId]) -> TypeId {
333 match self.resolve_function_call(func, arg_types) {
334 CallResult::Success(ret) => ret,
335 _ => TypeId::ERROR,
337 }
338 }
339
340 pub fn get_contextual_signature(
354 db: &dyn TypeDatabase,
355 type_id: TypeId,
356 ) -> Option<FunctionShape> {
357 Self::get_contextual_signature_for_arity(db, type_id, None)
358 }
359
360 pub fn get_contextual_signature_for_arity(
363 db: &dyn TypeDatabase,
364 type_id: TypeId,
365 arg_count: Option<usize>,
366 ) -> Option<FunctionShape> {
367 struct ContextualSignatureVisitor<'a> {
368 db: &'a dyn TypeDatabase,
369 arg_count: Option<usize>,
370 }
371
372 impl<'a> TypeVisitor for ContextualSignatureVisitor<'a> {
373 type Output = Option<FunctionShape>;
374
375 fn default_output() -> Self::Output {
376 None
377 }
378
379 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
380 None
381 }
382
383 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
384 None
385 }
386
387 fn visit_ref(&mut self, ref_id: u32) -> Self::Output {
388 self.visit_type(self.db, TypeId(ref_id))
391 }
392
393 fn visit_function(&mut self, shape_id: u32) -> Self::Output {
394 let shape = self.db.function_shape(FunctionShapeId(shape_id));
396 Some(shape.as_ref().clone())
397 }
398
399 fn visit_callable(&mut self, shape_id: u32) -> Self::Output {
400 let shape = self.db.callable_shape(CallableShapeId(shape_id));
401
402 let signatures = if shape.call_signatures.is_empty() {
405 &shape.construct_signatures
406 } else {
407 &shape.call_signatures
408 };
409
410 let sig = if let Some(count) = self.arg_count {
412 signatures
413 .iter()
414 .find(|sig| {
415 let min_args =
416 sig.params.iter().filter(|p| !p.optional && !p.rest).count();
417 let has_rest = sig.params.iter().any(|p| p.rest);
418 count >= min_args && (has_rest || count <= sig.params.len())
419 })
420 .or_else(|| signatures.first())
421 } else {
422 signatures.first()
423 };
424
425 sig.map(|sig| FunctionShape {
426 type_params: sig.type_params.clone(),
427 params: sig.params.clone(),
428 this_type: sig.this_type,
429 return_type: sig.return_type,
430 type_predicate: sig.type_predicate.clone(),
431 is_constructor: false,
432 is_method: sig.is_method,
433 })
434 }
435
436 fn visit_application(&mut self, app_id: u32) -> Self::Output {
437 use crate::types::TypeApplicationId;
438
439 let app = self.db.type_application(TypeApplicationId(app_id));
441
442 let base_shape = self.visit_type(self.db, app.base)?;
445
446 let subst =
450 TypeSubstitution::from_args(self.db, &base_shape.type_params, &app.args);
451
452 if subst.is_empty() {
454 return Some(base_shape);
455 }
456
457 let instantiated_params: Vec<ParamInfo> = base_shape
459 .params
460 .iter()
461 .map(|p| ParamInfo {
462 name: p.name,
463 type_id: instantiate_type(self.db, p.type_id, &subst),
464 optional: p.optional,
465 rest: p.rest,
466 })
467 .collect();
468
469 let instantiated_return = instantiate_type(self.db, base_shape.return_type, &subst);
470
471 let instantiated_this = base_shape
472 .this_type
473 .map(|t| instantiate_type(self.db, t, &subst));
474
475 let instantiated_predicate =
477 base_shape
478 .type_predicate
479 .as_ref()
480 .map(|pred| TypePredicate {
481 asserts: pred.asserts,
482 target: pred.target.clone(),
483 type_id: pred.type_id.map(|t| instantiate_type(self.db, t, &subst)),
484 parameter_index: pred.parameter_index,
485 });
486
487 Some(FunctionShape {
489 type_params: Vec::new(),
492 params: instantiated_params,
493 this_type: instantiated_this,
494 return_type: instantiated_return,
495 type_predicate: instantiated_predicate,
496 is_constructor: base_shape.is_constructor,
497 is_method: base_shape.is_method,
498 })
499 }
500
501 fn visit_intersection(&mut self, list_id: u32) -> Self::Output {
502 let members = self.db.type_list(TypeListId(list_id));
503 for &member in members.iter() {
504 if let Some(shape) = self.visit_type(self.db, member) {
505 return Some(shape);
506 }
507 }
508 None
509 }
510
511 }
513
514 let mut visitor = ContextualSignatureVisitor { db, arg_count };
515 visitor.visit_type(db, type_id)
516 }
517
518 pub fn resolve_call(&mut self, func_type: TypeId, arg_types: &[TypeId]) -> CallResult {
522 self.last_instantiated_predicate = None;
523 let key = match self.interner.lookup(func_type) {
525 Some(k) => k,
526 None => return CallResult::NotCallable { type_id: func_type },
527 };
528
529 match key {
530 TypeData::Function(f_id) => {
531 let shape = self.interner.function_shape(f_id);
532 self.resolve_function_call(shape.as_ref(), arg_types)
533 }
534 TypeData::Callable(c_id) => {
535 let shape = self.interner.callable_shape(c_id);
536 self.resolve_callable_call(shape.as_ref(), arg_types)
537 }
538 TypeData::Union(list_id) => {
539 self.resolve_union_call(func_type, list_id, arg_types)
542 }
543 TypeData::Intersection(list_id) => {
544 self.resolve_intersection_call(func_type, list_id, arg_types)
547 }
548 TypeData::Application(_app_id) => {
549 let evaluated = self.checker.evaluate_type(func_type);
552 if evaluated != func_type {
553 self.resolve_call(evaluated, arg_types)
554 } else {
555 CallResult::NotCallable { type_id: func_type }
556 }
557 }
558 TypeData::TypeParameter(param_info) => {
559 if let Some(constraint) = param_info.constraint {
562 self.resolve_call(constraint, arg_types)
563 } else {
564 CallResult::NotCallable { type_id: func_type }
565 }
566 }
567 TypeData::Lazy(_)
568 | TypeData::Conditional(_)
569 | TypeData::IndexAccess(_, _)
570 | TypeData::Mapped(_)
571 | TypeData::TemplateLiteral(_) => {
572 let resolved = crate::evaluate::evaluate_type(self.interner, func_type);
576 if resolved != func_type {
577 self.resolve_call(resolved, arg_types)
578 } else {
579 CallResult::NotCallable { type_id: func_type }
580 }
581 }
582 TypeData::Intrinsic(IntrinsicKind::Function | IntrinsicKind::Any) => {
585 CallResult::Success(TypeId::ANY)
586 }
587 TypeData::Error => CallResult::Success(TypeId::ERROR),
590 _ => CallResult::NotCallable { type_id: func_type },
591 }
592 }
593
594 fn resolve_union_call(
603 &mut self,
604 union_type: TypeId,
605 list_id: TypeListId,
606 arg_types: &[TypeId],
607 ) -> CallResult {
608 let members = self.interner.type_list(list_id);
609
610 let mut return_types = Vec::new();
612 let mut failures = Vec::new();
613
614 for &member in members.iter() {
615 let result = self.resolve_call(member, arg_types);
616 match result {
617 CallResult::Success(return_type) => {
618 return_types.push(return_type);
619 }
620 CallResult::NotCallable { .. } => {
621 return CallResult::NotCallable {
625 type_id: union_type,
626 };
627 }
628 other => {
629 failures.push(other);
631 }
632 }
633 }
634
635 if !return_types.is_empty() {
638 if return_types.len() == 1 {
639 return CallResult::Success(return_types[0]);
640 }
641 let union_result = self.interner.union(return_types);
643 CallResult::Success(union_result)
644 } else if !failures.is_empty() {
645 let all_arg_mismatches = failures
650 .iter()
651 .all(|f| matches!(f, CallResult::ArgumentTypeMismatch { .. }));
652
653 if all_arg_mismatches && !failures.is_empty() {
654 let mut param_types = Vec::new();
656 for failure in &failures {
657 if let CallResult::ArgumentTypeMismatch { expected, .. } = failure {
658 param_types.push(*expected);
659 }
660 }
661
662 let intersected_param = if param_types.len() == 1 {
665 param_types[0]
666 } else {
667 let mut result = param_types[0];
669 for ¶m_type in ¶m_types[1..] {
670 result = self.interner.intersection2(result, param_type);
671 }
672 result
673 };
674
675 let actual_arg_type =
678 if let Some(CallResult::ArgumentTypeMismatch { actual, .. }) = failures.first()
679 {
680 *actual
681 } else {
682 TypeId::ERROR
684 };
685
686 return CallResult::ArgumentTypeMismatch {
687 index: 0,
688 expected: intersected_param,
689 actual: actual_arg_type,
690 };
691 }
692
693 failures
695 .into_iter()
696 .next()
697 .unwrap_or(CallResult::NotCallable {
698 type_id: union_type,
699 })
700 } else {
701 CallResult::NotCallable {
703 type_id: union_type,
704 }
705 }
706 }
707
708 fn resolve_intersection_call(
717 &mut self,
718 intersection_type: TypeId,
719 list_id: TypeListId,
720 arg_types: &[TypeId],
721 ) -> CallResult {
722 let members = self.interner.type_list(list_id);
723
724 for &member in members.iter() {
728 let result = self.resolve_call(member, arg_types);
729 match result {
730 CallResult::Success(return_type) => {
731 return CallResult::Success(return_type);
733 }
734 CallResult::NotCallable { .. } => {
735 continue;
737 }
738 other => {
739 return other;
742 }
743 }
744 }
745
746 CallResult::NotCallable {
748 type_id: intersection_type,
749 }
750 }
751
752 fn expand_type_param(&self, ty: TypeId) -> TypeId {
755 match self.interner.lookup(ty) {
756 Some(TypeData::TypeParameter(tp)) => tp.constraint.unwrap_or(ty),
757 _ => ty,
758 }
759 }
760
761 pub(crate) fn resolve_function_call(
763 &mut self,
764 func: &FunctionShape,
765 arg_types: &[TypeId],
766 ) -> CallResult {
767 if !func.type_params.is_empty() {
769 return self.resolve_generic_call(func, arg_types);
770 }
771
772 if let Some(expected_this) = func.this_type {
774 if let Some(actual_this) = self.actual_this_type {
775 if !self.checker.is_assignable_to(actual_this, expected_this) {
776 return CallResult::ThisTypeMismatch {
777 expected_this,
778 actual_this,
779 };
780 }
781 }
782 else if !self.checker.is_assignable_to(TypeId::VOID, expected_this) {
785 return CallResult::ThisTypeMismatch {
786 expected_this,
787 actual_this: TypeId::VOID,
788 };
789 }
790 }
791
792 let (min_args, max_args) = self.arg_count_bounds(&func.params);
794
795 if arg_types.len() < min_args {
796 return CallResult::ArgumentCountMismatch {
797 expected_min: min_args,
798 expected_max: max_args,
799 actual: arg_types.len(),
800 };
801 }
802
803 if let Some(max) = max_args
804 && arg_types.len() > max
805 {
806 return CallResult::ArgumentCountMismatch {
807 expected_min: min_args,
808 expected_max: Some(max),
809 actual: arg_types.len(),
810 };
811 }
812
813 if let Some(result) = self.check_argument_types(&func.params, arg_types, func.is_method) {
816 return result;
817 }
818
819 CallResult::Success(func.return_type)
820 }
821
822 fn check_argument_types(
824 &mut self,
825 params: &[ParamInfo],
826 arg_types: &[TypeId],
827 allow_bivariant_callbacks: bool,
828 ) -> Option<CallResult> {
829 self.check_argument_types_with(params, arg_types, false, allow_bivariant_callbacks)
830 }
831
832 pub(crate) fn check_argument_types_with(
833 &mut self,
834 params: &[ParamInfo],
835 arg_types: &[TypeId],
836 strict: bool,
837 allow_bivariant_callbacks: bool,
838 ) -> Option<CallResult> {
839 let arg_count = arg_types.len();
840 for (i, arg_type) in arg_types.iter().enumerate() {
841 let Some(param_type) = self.param_type_for_arg_index(params, i, arg_count) else {
842 break;
843 };
844
845 if *arg_type == param_type {
846 continue;
847 }
848
849 let expanded_arg_type = match self.interner.lookup(param_type) {
858 Some(TypeData::TypeParameter(_) | TypeData::Infer(_)) => *arg_type,
859 _ => self.expand_type_param(*arg_type),
860 };
861
862 if expanded_arg_type == param_type {
863 continue;
864 }
865
866 let assignable = if allow_bivariant_callbacks || self.force_bivariant_callbacks {
867 self.checker
868 .is_assignable_to_bivariant_callback(expanded_arg_type, param_type)
869 } else if strict {
870 let result = self
871 .checker
872 .is_assignable_to_strict(expanded_arg_type, param_type);
873 if !result {
874 tracing::debug!(
875 "Strict assignability failed at index {}: {:?} <: {:?}",
876 i,
877 self.interner.lookup(expanded_arg_type),
878 self.interner.lookup(param_type)
879 );
880 }
881 result
882 } else {
883 self.checker.is_assignable_to(expanded_arg_type, param_type)
884 };
885
886 if !assignable {
887 return Some(CallResult::ArgumentTypeMismatch {
888 index: i,
889 expected: param_type,
890 actual: *arg_type,
891 });
892 }
893 }
894 None
895 }
896
897 pub(crate) fn arg_count_bounds(&self, params: &[ParamInfo]) -> (usize, Option<usize>) {
898 let required = params.iter().filter(|p| !p.optional && !p.rest).count();
899 let rest_param = params.last().filter(|param| param.rest);
900 let Some(rest_param) = rest_param else {
901 return (required, Some(params.len()));
902 };
903
904 let rest_param_type = self.unwrap_readonly(rest_param.type_id);
905 match self.interner.lookup(rest_param_type) {
906 Some(TypeData::Tuple(elements)) => {
907 let elements = self.interner.tuple_list(elements);
908 let (rest_min, rest_max) = self.tuple_length_bounds(&elements);
909 let min = required + rest_min;
910 let max = rest_max.map(|max| required + max);
911 (min, max)
912 }
913 _ => (required, None),
914 }
915 }
916
917 pub(crate) fn param_type_for_arg_index(
918 &self,
919 params: &[ParamInfo],
920 arg_index: usize,
921 arg_count: usize,
922 ) -> Option<TypeId> {
923 let rest_param = params.last().filter(|param| param.rest);
924 let rest_start = if rest_param.is_some() {
925 params.len().saturating_sub(1)
926 } else {
927 params.len()
928 };
929
930 if arg_index < rest_start {
931 return Some(params[arg_index].type_id);
932 }
933
934 let rest_param = rest_param?;
935 let offset = arg_index - rest_start;
936 let rest_arg_count = arg_count.saturating_sub(rest_start);
937
938 let rest_param_type = self.unwrap_readonly(rest_param.type_id);
939 trace!(
940 rest_param_type_id = %rest_param_type.0,
941 rest_param_type_key = ?self.interner.lookup(rest_param_type),
942 "Extracting element type from rest parameter"
943 );
944 match self.interner.lookup(rest_param_type) {
945 Some(TypeData::Array(elem)) => {
946 trace!(
947 elem_type_id = %elem.0,
948 elem_type_key = ?self.interner.lookup(elem),
949 "Extracted array element type"
950 );
951 Some(elem)
952 }
953 Some(TypeData::Tuple(elements)) => {
954 let elements = self.interner.tuple_list(elements);
955 self.tuple_rest_element_type(&elements, offset, rest_arg_count)
956 }
957 other => {
958 trace!(?other, "Rest param is not Array or Tuple, returning as-is");
959 Some(rest_param_type)
960 }
961 }
962 }
963
964 fn tuple_length_bounds(&self, elements: &[TupleElement]) -> (usize, Option<usize>) {
965 let mut min = 0usize;
966 let mut max = 0usize;
967 let mut variadic = false;
968
969 for elem in elements {
970 if elem.rest {
971 let expansion = self.expand_tuple_rest(elem.type_id);
972 for fixed in expansion.fixed {
973 max += 1;
974 if !fixed.optional {
975 min += 1;
976 }
977 }
978 if expansion.variadic.is_some() {
979 variadic = true;
980 }
981 for tail_elem in expansion.tail {
983 max += 1;
984 if !tail_elem.optional {
985 min += 1;
986 }
987 }
988 continue;
989 }
990 max += 1;
991 if !elem.optional {
992 min += 1;
993 }
994 }
995
996 (min, if variadic { None } else { Some(max) })
997 }
998
999 fn tuple_rest_element_type(
1000 &self,
1001 elements: &[TupleElement],
1002 offset: usize,
1003 rest_arg_count: usize,
1004 ) -> Option<TypeId> {
1005 let rest_index = elements.iter().position(|elem| elem.rest);
1006 let Some(rest_index) = rest_index else {
1007 return elements.get(offset).map(|elem| elem.type_id);
1008 };
1009
1010 let (prefix, rest_and_tail) = elements.split_at(rest_index);
1011 let rest_elem = &rest_and_tail[0];
1012 let outer_tail = &rest_and_tail[1..];
1013
1014 let expansion = self.expand_tuple_rest(rest_elem.type_id);
1015 let prefix_len = prefix.len();
1016 let rest_fixed_len = expansion.fixed.len();
1017 let expansion_tail_len = expansion.tail.len();
1018 let outer_tail_len = outer_tail.len();
1019 let total_suffix_len = expansion_tail_len + outer_tail_len;
1021
1022 if let Some(variadic) = expansion.variadic {
1023 let suffix_start = rest_arg_count.saturating_sub(total_suffix_len);
1024 if offset >= suffix_start {
1025 let suffix_index = offset - suffix_start;
1026 if suffix_index < expansion_tail_len {
1028 return Some(expansion.tail[suffix_index].type_id);
1029 }
1030 let outer_index = suffix_index - expansion_tail_len;
1031 return outer_tail.get(outer_index).map(|elem| elem.type_id);
1032 }
1033 if offset < prefix_len {
1034 return Some(prefix[offset].type_id);
1035 }
1036 let fixed_end = prefix_len + rest_fixed_len;
1037 if offset < fixed_end {
1038 return Some(expansion.fixed[offset - prefix_len].type_id);
1039 }
1040 return Some(variadic);
1041 }
1042
1043 let mut index = offset;
1045 if index < prefix_len {
1046 return Some(prefix[index].type_id);
1047 }
1048 index -= prefix_len;
1049 if index < rest_fixed_len {
1050 return Some(expansion.fixed[index].type_id);
1051 }
1052 index -= rest_fixed_len;
1053 if index < expansion_tail_len {
1054 return Some(expansion.tail[index].type_id);
1055 }
1056 index -= expansion_tail_len;
1057 outer_tail.get(index).map(|elem| elem.type_id)
1058 }
1059
1060 pub(crate) fn rest_element_type(&self, type_id: TypeId) -> TypeId {
1061 match self.interner.lookup(type_id) {
1062 Some(TypeData::Array(elem)) => elem,
1063 _ => type_id,
1064 }
1065 }
1066
1067 const MAX_UNWRAP_ITERATIONS: usize = 1000;
1069
1070 fn unwrap_readonly(&self, mut type_id: TypeId) -> TypeId {
1071 let mut iterations = 0;
1072 loop {
1073 iterations += 1;
1074 if iterations > Self::MAX_UNWRAP_ITERATIONS {
1075 return type_id;
1077 }
1078 match self.interner.lookup(type_id) {
1079 Some(TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner)) => {
1080 type_id = inner;
1081 }
1082 _ => return type_id,
1083 }
1084 }
1085 }
1086
1087 fn expand_tuple_rest(&self, type_id: TypeId) -> TupleRestExpansion {
1088 match self.interner.lookup(type_id) {
1089 Some(TypeData::Array(elem)) => TupleRestExpansion {
1090 fixed: Vec::new(),
1091 variadic: Some(elem),
1092 tail: Vec::new(),
1093 },
1094 Some(TypeData::Tuple(elements)) => {
1095 let elements = self.interner.tuple_list(elements);
1096 let mut fixed = Vec::new();
1097 for (i, elem) in elements.iter().enumerate() {
1098 if elem.rest {
1099 let inner = self.expand_tuple_rest(elem.type_id);
1100 fixed.extend(inner.fixed);
1101 let mut tail = inner.tail;
1103 tail.extend(elements[i + 1..].iter().cloned());
1104 return TupleRestExpansion {
1105 fixed,
1106 variadic: inner.variadic,
1107 tail,
1108 };
1109 }
1110 fixed.push(elem.clone());
1111 }
1112 TupleRestExpansion {
1113 fixed,
1114 variadic: None,
1115 tail: Vec::new(),
1116 }
1117 }
1118 _ => TupleRestExpansion {
1119 fixed: Vec::new(),
1120 variadic: Some(type_id),
1121 tail: Vec::new(),
1122 },
1123 }
1124 }
1125
1126 pub(crate) fn rest_tuple_inference_target(
1127 &mut self,
1128 params: &[ParamInfo],
1129 arg_types: &[TypeId],
1130 var_map: &FxHashMap<TypeId, crate::infer::InferenceVar>,
1131 ) -> Option<(usize, TypeId, TypeId)> {
1132 let rest_param = params.last().filter(|param| param.rest)?;
1133 let rest_start = params.len().saturating_sub(1);
1134
1135 let rest_param_type = self.unwrap_readonly(rest_param.type_id);
1136 let target = match self.interner.lookup(rest_param_type) {
1137 Some(TypeData::TypeParameter(_)) if var_map.contains_key(&rest_param_type) => {
1138 Some((rest_start, rest_param_type, 0))
1139 }
1140 Some(TypeData::Tuple(elements)) => {
1141 let elements = self.interner.tuple_list(elements);
1142 elements.iter().enumerate().find_map(|(i, elem)| {
1143 if !elem.rest {
1144 return None;
1145 }
1146 if !var_map.contains_key(&elem.type_id) {
1147 return None;
1148 }
1149
1150 let tail = &elements[i + 1..];
1153 let min_index = rest_start + i;
1154 let mut trailing_count = 0usize;
1155 let mut arg_index = arg_types.len();
1156 for tail_elem in tail.iter().rev() {
1157 if arg_index <= min_index {
1158 break;
1159 }
1160 let arg_type = arg_types[arg_index - 1];
1161 let assignable = self.checker.is_assignable_to(arg_type, tail_elem.type_id);
1162 if tail_elem.optional && !assignable {
1163 break;
1164 }
1165 trailing_count += 1;
1166 arg_index -= 1;
1167 }
1168 Some((rest_start + i, elem.type_id, trailing_count))
1169 })
1170 }
1171 _ => None,
1172 }?;
1173
1174 let (start_index, target_type, trailing_count) = target;
1175 if start_index >= arg_types.len() {
1176 return None;
1177 }
1178
1179 let end_index = arg_types.len().saturating_sub(trailing_count);
1189 let tuple_elements: Vec<TupleElement> = if start_index < end_index {
1190 arg_types[start_index..end_index]
1191 .iter()
1192 .map(|&ty| TupleElement {
1193 type_id: ty,
1194 name: None,
1195 optional: false,
1196 rest: false,
1197 })
1198 .collect()
1199 } else {
1200 Vec::new()
1201 };
1202 Some((
1203 start_index,
1204 target_type,
1205 self.interner.tuple(tuple_elements),
1206 ))
1207 }
1208
1209 pub(crate) fn type_contains_placeholder(
1210 &self,
1211 ty: TypeId,
1212 var_map: &FxHashMap<TypeId, crate::infer::InferenceVar>,
1213 visited: &mut FxHashSet<TypeId>,
1214 ) -> bool {
1215 if var_map.contains_key(&ty) {
1216 return true;
1217 }
1218 if !visited.insert(ty) {
1219 return false;
1220 }
1221
1222 let key = match self.interner.lookup(ty) {
1223 Some(key) => key,
1224 None => return false,
1225 };
1226
1227 match key {
1228 TypeData::Array(elem) => self.type_contains_placeholder(elem, var_map, visited),
1229 TypeData::Tuple(elements) => {
1230 let elements = self.interner.tuple_list(elements);
1231 elements
1232 .iter()
1233 .any(|elem| self.type_contains_placeholder(elem.type_id, var_map, visited))
1234 }
1235 TypeData::Union(members) | TypeData::Intersection(members) => {
1236 let members = self.interner.type_list(members);
1237 members
1238 .iter()
1239 .any(|&member| self.type_contains_placeholder(member, var_map, visited))
1240 }
1241 TypeData::Object(shape_id) => {
1242 let shape = self.interner.object_shape(shape_id);
1243 shape
1244 .properties
1245 .iter()
1246 .any(|prop| self.type_contains_placeholder(prop.type_id, var_map, visited))
1247 }
1248 TypeData::ObjectWithIndex(shape_id) => {
1249 let shape = self.interner.object_shape(shape_id);
1250 shape
1251 .properties
1252 .iter()
1253 .any(|prop| self.type_contains_placeholder(prop.type_id, var_map, visited))
1254 || shape.string_index.as_ref().is_some_and(|idx| {
1255 self.type_contains_placeholder(idx.key_type, var_map, visited)
1256 || self.type_contains_placeholder(idx.value_type, var_map, visited)
1257 })
1258 || shape.number_index.as_ref().is_some_and(|idx| {
1259 self.type_contains_placeholder(idx.key_type, var_map, visited)
1260 || self.type_contains_placeholder(idx.value_type, var_map, visited)
1261 })
1262 }
1263 TypeData::Application(app_id) => {
1264 let app = self.interner.type_application(app_id);
1265 self.type_contains_placeholder(app.base, var_map, visited)
1266 || app
1267 .args
1268 .iter()
1269 .any(|&arg| self.type_contains_placeholder(arg, var_map, visited))
1270 }
1271 TypeData::Function(shape_id) => {
1272 let shape = self.interner.function_shape(shape_id);
1273 shape.type_params.iter().any(|tp| {
1274 tp.constraint.is_some_and(|constraint| {
1275 self.type_contains_placeholder(constraint, var_map, visited)
1276 }) || tp.default.is_some_and(|default| {
1277 self.type_contains_placeholder(default, var_map, visited)
1278 })
1279 }) || shape
1280 .params
1281 .iter()
1282 .any(|param| self.type_contains_placeholder(param.type_id, var_map, visited))
1283 || shape.this_type.is_some_and(|this_type| {
1284 self.type_contains_placeholder(this_type, var_map, visited)
1285 })
1286 || self.type_contains_placeholder(shape.return_type, var_map, visited)
1287 || shape.type_predicate.as_ref().is_some_and(|pred| {
1288 pred.type_id
1289 .is_some_and(|ty| self.type_contains_placeholder(ty, var_map, visited))
1290 })
1291 }
1292 TypeData::Callable(shape_id) => {
1293 let shape = self.interner.callable_shape(shape_id);
1294 let in_call = shape.call_signatures.iter().any(|sig| {
1295 sig.type_params.iter().any(|tp| {
1296 tp.constraint.is_some_and(|constraint| {
1297 self.type_contains_placeholder(constraint, var_map, visited)
1298 }) || tp.default.is_some_and(|default| {
1299 self.type_contains_placeholder(default, var_map, visited)
1300 })
1301 }) || sig.params.iter().any(|param| {
1302 self.type_contains_placeholder(param.type_id, var_map, visited)
1303 }) || sig.this_type.is_some_and(|this_type| {
1304 self.type_contains_placeholder(this_type, var_map, visited)
1305 }) || self.type_contains_placeholder(sig.return_type, var_map, visited)
1306 || sig.type_predicate.as_ref().is_some_and(|pred| {
1307 pred.type_id.is_some_and(|ty| {
1308 self.type_contains_placeholder(ty, var_map, visited)
1309 })
1310 })
1311 });
1312 if in_call {
1313 return true;
1314 }
1315 let in_construct = shape.construct_signatures.iter().any(|sig| {
1316 sig.type_params.iter().any(|tp| {
1317 tp.constraint.is_some_and(|constraint| {
1318 self.type_contains_placeholder(constraint, var_map, visited)
1319 }) || tp.default.is_some_and(|default| {
1320 self.type_contains_placeholder(default, var_map, visited)
1321 })
1322 }) || sig.params.iter().any(|param| {
1323 self.type_contains_placeholder(param.type_id, var_map, visited)
1324 }) || sig.this_type.is_some_and(|this_type| {
1325 self.type_contains_placeholder(this_type, var_map, visited)
1326 }) || self.type_contains_placeholder(sig.return_type, var_map, visited)
1327 || sig.type_predicate.as_ref().is_some_and(|pred| {
1328 pred.type_id.is_some_and(|ty| {
1329 self.type_contains_placeholder(ty, var_map, visited)
1330 })
1331 })
1332 });
1333 if in_construct {
1334 return true;
1335 }
1336 shape
1337 .properties
1338 .iter()
1339 .any(|prop| self.type_contains_placeholder(prop.type_id, var_map, visited))
1340 }
1341 TypeData::Conditional(cond_id) => {
1342 let cond = self.interner.conditional_type(cond_id);
1343 self.type_contains_placeholder(cond.check_type, var_map, visited)
1344 || self.type_contains_placeholder(cond.extends_type, var_map, visited)
1345 || self.type_contains_placeholder(cond.true_type, var_map, visited)
1346 || self.type_contains_placeholder(cond.false_type, var_map, visited)
1347 }
1348 TypeData::Mapped(mapped_id) => {
1349 let mapped = self.interner.mapped_type(mapped_id);
1350 mapped.type_param.constraint.is_some_and(|constraint| {
1351 self.type_contains_placeholder(constraint, var_map, visited)
1352 }) || mapped.type_param.default.is_some_and(|default| {
1353 self.type_contains_placeholder(default, var_map, visited)
1354 }) || self.type_contains_placeholder(mapped.constraint, var_map, visited)
1355 || self.type_contains_placeholder(mapped.template, var_map, visited)
1356 }
1357 TypeData::IndexAccess(obj, idx) => {
1358 self.type_contains_placeholder(obj, var_map, visited)
1359 || self.type_contains_placeholder(idx, var_map, visited)
1360 }
1361 TypeData::KeyOf(operand)
1362 | TypeData::ReadonlyType(operand)
1363 | TypeData::NoInfer(operand) => {
1364 self.type_contains_placeholder(operand, var_map, visited)
1365 }
1366 TypeData::TemplateLiteral(spans) => {
1367 let spans = self.interner.template_list(spans);
1368 spans.iter().any(|span| match span {
1369 TemplateSpan::Text(_) => false,
1370 TemplateSpan::Type(inner) => {
1371 self.type_contains_placeholder(*inner, var_map, visited)
1372 }
1373 })
1374 }
1375 TypeData::StringIntrinsic { type_arg, .. } => {
1376 self.type_contains_placeholder(type_arg, var_map, visited)
1377 }
1378 TypeData::Enum(_def_id, member_type) => {
1379 self.type_contains_placeholder(member_type, var_map, visited)
1380 }
1381 TypeData::TypeParameter(_)
1382 | TypeData::Infer(_)
1383 | TypeData::Intrinsic(_)
1384 | TypeData::Literal(_)
1385 | TypeData::Lazy(_)
1386 | TypeData::Recursive(_)
1387 | TypeData::BoundParameter(_)
1388 | TypeData::TypeQuery(_)
1389 | TypeData::UniqueSymbol(_)
1390 | TypeData::ThisType
1391 | TypeData::ModuleNamespace(_)
1392 | TypeData::Error => false,
1393 }
1394 }
1395
1396 pub(crate) fn is_contextually_sensitive(&self, type_id: TypeId) -> bool {
1407 let key = match self.interner.lookup(type_id) {
1408 Some(key) => key,
1409 None => return false,
1410 };
1411
1412 match key {
1413 TypeData::Function(_) | TypeData::Callable(_) => true,
1416
1417 TypeData::Union(members) | TypeData::Intersection(members) => {
1419 let members = self.interner.type_list(members);
1420 members
1421 .iter()
1422 .any(|&member| self.is_contextually_sensitive(member))
1423 }
1424
1425 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
1427 let shape = self.interner.object_shape(shape_id);
1428 shape
1429 .properties
1430 .iter()
1431 .any(|prop| self.is_contextually_sensitive(prop.type_id))
1432 }
1433
1434 TypeData::Array(elem) => self.is_contextually_sensitive(elem),
1436
1437 TypeData::Tuple(elements) => {
1439 let elements = self.interner.tuple_list(elements);
1440 elements
1441 .iter()
1442 .any(|elem| self.is_contextually_sensitive(elem.type_id))
1443 }
1444
1445 TypeData::Application(app_id) => {
1447 let app = self.interner.type_application(app_id);
1448 self.is_contextually_sensitive(app.base)
1449 || app
1450 .args
1451 .iter()
1452 .any(|&arg| self.is_contextually_sensitive(arg))
1453 }
1454
1455 TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner) => {
1457 self.is_contextually_sensitive(inner)
1458 }
1459
1460 TypeData::TypeParameter(info) | TypeData::Infer(info) => info
1462 .constraint
1463 .is_some_and(|constraint| self.is_contextually_sensitive(constraint)),
1464
1465 TypeData::IndexAccess(obj, key) => {
1467 self.is_contextually_sensitive(obj) || self.is_contextually_sensitive(key)
1468 }
1469
1470 TypeData::Conditional(cond_id) => {
1472 let cond = self.interner.conditional_type(cond_id);
1473 self.is_contextually_sensitive(cond.check_type)
1474 || self.is_contextually_sensitive(cond.extends_type)
1475 || self.is_contextually_sensitive(cond.true_type)
1476 || self.is_contextually_sensitive(cond.false_type)
1477 }
1478
1479 TypeData::Mapped(mapped_id) => {
1481 let mapped = self.interner.mapped_type(mapped_id);
1482 self.is_contextually_sensitive(mapped.constraint)
1483 || self.is_contextually_sensitive(mapped.template)
1484 }
1485
1486 TypeData::KeyOf(operand)
1488 | TypeData::StringIntrinsic {
1489 type_arg: operand, ..
1490 } => self.is_contextually_sensitive(operand),
1491
1492 TypeData::Enum(_def_id, member_type) => self.is_contextually_sensitive(member_type),
1494
1495 TypeData::TemplateLiteral(spans) => {
1497 let spans = self.interner.template_list(spans);
1498 spans.iter().any(|span| match span {
1499 TemplateSpan::Text(_) => false,
1500 TemplateSpan::Type(inner) => self.is_contextually_sensitive(*inner),
1501 })
1502 }
1503
1504 TypeData::Intrinsic(_)
1506 | TypeData::Literal(_)
1507 | TypeData::Lazy(_)
1508 | TypeData::Recursive(_)
1509 | TypeData::BoundParameter(_)
1510 | TypeData::TypeQuery(_)
1511 | TypeData::UniqueSymbol(_)
1512 | TypeData::ThisType
1513 | TypeData::ModuleNamespace(_)
1514 | TypeData::Error => false,
1515 }
1516 }
1517
1518 pub(crate) fn resolve_callable_call(
1520 &mut self,
1521 callable: &CallableShape,
1522 arg_types: &[TypeId],
1523 ) -> CallResult {
1524 if callable.call_signatures.is_empty() {
1527 return CallResult::NotCallable {
1528 type_id: self.interner.callable(callable.clone()),
1529 };
1530 }
1531
1532 if callable.call_signatures.len() == 1 {
1533 let sig = &callable.call_signatures[0];
1534 let func = FunctionShape {
1535 params: sig.params.clone(),
1536 this_type: sig.this_type,
1537 return_type: sig.return_type,
1538 type_params: sig.type_params.clone(),
1539 type_predicate: sig.type_predicate.clone(),
1540 is_constructor: false,
1541 is_method: sig.is_method,
1542 };
1543 return self.resolve_function_call(&func, arg_types);
1544 }
1545
1546 let mut failures = Vec::new();
1548 let mut all_arg_count_mismatches = true;
1549 let mut min_expected = usize::MAX;
1550 let mut max_expected = 0;
1551 let mut any_has_rest = false;
1552 let actual_count = arg_types.len();
1553 let mut exact_expected_counts = FxHashSet::default();
1554 let mut type_mismatch_count: usize = 0;
1558 let mut first_type_mismatch: Option<(usize, TypeId, TypeId)> = None; let mut all_mismatches_identical = true;
1560 let mut has_non_count_non_type_failure = false;
1561
1562 for sig in &callable.call_signatures {
1563 let func = FunctionShape {
1565 params: sig.params.clone(),
1566 this_type: sig.this_type,
1567 return_type: sig.return_type,
1568 type_params: sig.type_params.clone(),
1569 type_predicate: sig.type_predicate.clone(),
1570 is_constructor: false,
1571 is_method: sig.is_method,
1572 };
1573 tracing::debug!("resolve_callable_call: signature = {sig:?}");
1574
1575 match self.resolve_function_call(&func, arg_types) {
1576 CallResult::Success(ret) => return CallResult::Success(ret),
1577 CallResult::TypeParameterConstraintViolation { return_type, .. } => {
1578 return CallResult::Success(return_type);
1581 }
1582 CallResult::ArgumentTypeMismatch {
1583 index,
1584 expected,
1585 actual,
1586 } => {
1587 all_arg_count_mismatches = false;
1588 type_mismatch_count += 1;
1589 if type_mismatch_count == 1 {
1590 first_type_mismatch = Some((index, expected, actual));
1591 } else if first_type_mismatch != Some((index, expected, actual)) {
1592 all_mismatches_identical = false;
1593 }
1594 failures.push(
1595 crate::diagnostics::PendingDiagnosticBuilder::argument_not_assignable(
1596 actual, expected,
1597 ),
1598 );
1599 }
1600 CallResult::ArgumentCountMismatch {
1601 expected_min,
1602 expected_max,
1603 actual,
1604 } => {
1605 if expected_max.is_none() {
1606 any_has_rest = true;
1607 } else if expected_min == expected_max.unwrap_or(expected_min) {
1608 exact_expected_counts.insert(expected_min);
1609 }
1610 let expected = expected_max.unwrap_or(expected_min);
1611 min_expected = min_expected.min(expected_min);
1612 max_expected = max_expected.max(expected);
1613 failures.push(
1614 crate::diagnostics::PendingDiagnosticBuilder::argument_count_mismatch(
1615 expected, actual,
1616 ),
1617 );
1618 }
1619 _ => {
1620 all_arg_count_mismatches = false;
1621 has_non_count_non_type_failure = true;
1622 }
1623 }
1624 }
1625
1626 if all_arg_count_mismatches && !failures.is_empty() {
1628 if !any_has_rest
1629 && !exact_expected_counts.is_empty()
1630 && !exact_expected_counts.contains(&actual_count)
1631 {
1632 let mut lower = None;
1633 let mut upper = None;
1634 for &count in &exact_expected_counts {
1635 if count < actual_count {
1636 lower = Some(lower.map_or(count, |prev: usize| prev.max(count)));
1637 } else if count > actual_count {
1638 upper = Some(upper.map_or(count, |prev: usize| prev.min(count)));
1639 }
1640 }
1641 if let (Some(expected_low), Some(expected_high)) = (lower, upper) {
1642 return CallResult::OverloadArgumentCountMismatch {
1643 actual: actual_count,
1644 expected_low,
1645 expected_high,
1646 };
1647 }
1648 }
1649 return CallResult::ArgumentCountMismatch {
1650 expected_min: min_expected,
1651 expected_max: if any_has_rest {
1652 None
1653 } else if max_expected > min_expected {
1654 Some(max_expected)
1655 } else {
1656 Some(min_expected)
1657 },
1658 actual: actual_count,
1659 };
1660 }
1661
1662 if !has_non_count_non_type_failure
1666 && type_mismatch_count > 0
1667 && all_mismatches_identical
1668 && let Some((index, expected, actual)) = first_type_mismatch
1669 {
1670 return CallResult::ArgumentTypeMismatch {
1671 index,
1672 expected,
1673 actual,
1674 };
1675 }
1676
1677 CallResult::NoOverloadMatch {
1679 func_type: self.interner.callable(callable.clone()),
1680 arg_types: arg_types.to_vec(),
1681 failures,
1682 fallback_return: callable
1683 .call_signatures
1684 .first()
1685 .map(|s| s.return_type)
1686 .unwrap_or(TypeId::ANY),
1687 }
1688 }
1689}
1690
1691pub fn infer_call_signature<C: AssignabilityChecker>(
1692 interner: &dyn QueryDatabase,
1693 checker: &mut C,
1694 sig: &CallSignature,
1695 arg_types: &[TypeId],
1696) -> TypeId {
1697 let mut evaluator = CallEvaluator::new(interner, checker);
1698 evaluator.infer_call_signature(sig, arg_types)
1699}
1700
1701pub fn infer_generic_function<C: AssignabilityChecker>(
1702 interner: &dyn QueryDatabase,
1703 checker: &mut C,
1704 func: &FunctionShape,
1705 arg_types: &[TypeId],
1706) -> TypeId {
1707 let mut evaluator = CallEvaluator::new(interner, checker);
1708 evaluator.infer_generic_function(func, arg_types)
1709}
1710
1711pub fn resolve_call_with_checker<C: AssignabilityChecker>(
1712 interner: &dyn QueryDatabase,
1713 checker: &mut C,
1714 func_type: TypeId,
1715 arg_types: &[TypeId],
1716 force_bivariant_callbacks: bool,
1717 contextual_type: Option<TypeId>,
1718 actual_this_type: Option<TypeId>,
1719) -> (CallResult, Option<(TypePredicate, Vec<ParamInfo>)>) {
1720 let mut evaluator = CallEvaluator::new(interner, checker);
1721 evaluator.set_force_bivariant_callbacks(force_bivariant_callbacks);
1722 evaluator.set_contextual_type(contextual_type);
1723 evaluator.set_actual_this_type(actual_this_type);
1724 let result = evaluator.resolve_call(func_type, arg_types);
1725 let predicate = evaluator.last_instantiated_predicate.take();
1726 (result, predicate)
1727}
1728
1729pub fn resolve_new_with_checker<C: AssignabilityChecker>(
1730 interner: &dyn QueryDatabase,
1731 checker: &mut C,
1732 type_id: TypeId,
1733 arg_types: &[TypeId],
1734 force_bivariant_callbacks: bool,
1735) -> CallResult {
1736 let mut evaluator = CallEvaluator::new(interner, checker);
1737 evaluator.set_force_bivariant_callbacks(force_bivariant_callbacks);
1738 evaluator.resolve_new(type_id, arg_types)
1739}
1740
1741pub fn compute_contextual_types_with_compat_checker<'a, R, F>(
1742 interner: &'a dyn QueryDatabase,
1743 resolver: &'a R,
1744 shape: &FunctionShape,
1745 arg_types: &[TypeId],
1746 contextual_type: Option<TypeId>,
1747 configure_checker: F,
1748) -> TypeSubstitution
1749where
1750 R: crate::TypeResolver,
1751 F: FnOnce(&mut crate::CompatChecker<'a, R>),
1752{
1753 let mut checker = crate::CompatChecker::with_resolver(interner, resolver);
1754 configure_checker(&mut checker);
1755
1756 let mut evaluator = CallEvaluator::new(interner, &mut checker);
1757 evaluator.set_contextual_type(contextual_type);
1758 evaluator.compute_contextual_types(shape, arg_types)
1759}
1760
1761pub fn get_contextual_signature_with_compat_checker(
1762 db: &dyn TypeDatabase,
1763 type_id: TypeId,
1764) -> Option<FunctionShape> {
1765 CallEvaluator::<crate::CompatChecker>::get_contextual_signature(db, type_id)
1766}
1767
1768pub use crate::operations_generics::{GenericInstantiationResult, solve_generic_instantiation};
1770pub use crate::operations_iterators::{
1771 IteratorInfo, get_async_iterable_element_type, get_iterator_info,
1772};
1773
1774#[cfg(test)]
1775#[path = "../tests/operations_tests.rs"]
1776mod tests;