1use crate::TypeDatabase;
13#[cfg(test)]
14use crate::types::*;
15use crate::types::{
16 CallableShapeId, FunctionShapeId, IntrinsicKind, LiteralValue, ObjectShapeId, ParamInfo,
17 TupleListId, TypeApplicationId, TypeData, TypeId, TypeListId,
18};
19use crate::visitor::TypeVisitor;
20
21fn collect_single_or_union(db: &dyn TypeDatabase, types: Vec<TypeId>) -> Option<TypeId> {
32 match types.len() {
33 0 => None,
34 1 => Some(types[0]),
35 _ => Some(db.union(types)),
36 }
37}
38
39struct ThisTypeExtractor<'a> {
45 db: &'a dyn TypeDatabase,
46}
47
48impl<'a> ThisTypeExtractor<'a> {
49 fn new(db: &'a dyn TypeDatabase) -> Self {
50 Self { db }
51 }
52
53 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
54 self.visit_type(self.db, type_id)
55 }
56}
57
58impl<'a> TypeVisitor for ThisTypeExtractor<'a> {
59 type Output = Option<TypeId>;
60
61 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
62 None
63 }
64
65 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
66 None
67 }
68
69 fn visit_function(&mut self, shape_id: u32) -> Self::Output {
70 self.db.function_shape(FunctionShapeId(shape_id)).this_type
71 }
72
73 fn visit_callable(&mut self, shape_id: u32) -> Self::Output {
74 let shape = self.db.callable_shape(CallableShapeId(shape_id));
75 let this_types: Vec<TypeId> = shape
77 .call_signatures
78 .iter()
79 .filter_map(|sig| sig.this_type)
80 .collect();
81
82 collect_single_or_union(self.db, this_types)
83 }
84
85 fn default_output() -> Self::Output {
86 None
87 }
88}
89
90struct ReturnTypeExtractor<'a> {
92 db: &'a dyn TypeDatabase,
93}
94
95impl<'a> ReturnTypeExtractor<'a> {
96 fn new(db: &'a dyn TypeDatabase) -> Self {
97 Self { db }
98 }
99
100 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
101 self.visit_type(self.db, type_id)
102 }
103}
104
105impl<'a> TypeVisitor for ReturnTypeExtractor<'a> {
106 type Output = Option<TypeId>;
107
108 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
109 None
110 }
111
112 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
113 None
114 }
115
116 fn visit_function(&mut self, shape_id: u32) -> Self::Output {
117 Some(
118 self.db
119 .function_shape(FunctionShapeId(shape_id))
120 .return_type,
121 )
122 }
123
124 fn visit_callable(&mut self, shape_id: u32) -> Self::Output {
125 let shape = self.db.callable_shape(CallableShapeId(shape_id));
126 let return_types: Vec<TypeId> = shape
128 .call_signatures
129 .iter()
130 .map(|sig| sig.return_type)
131 .collect();
132
133 collect_single_or_union(self.db, return_types)
134 }
135
136 fn visit_union(&mut self, list_id: u32) -> Self::Output {
137 let members = self.db.type_list(TypeListId(list_id));
140 let types: Vec<TypeId> = members
141 .iter()
142 .filter_map(|&member| {
143 let mut extractor = ReturnTypeExtractor::new(self.db);
144 extractor.extract(member)
145 })
146 .collect();
147 collect_single_or_union(self.db, types)
148 }
149
150 fn default_output() -> Self::Output {
151 None
152 }
153}
154
155struct ThisTypeMarkerExtractor<'a> {
167 db: &'a dyn TypeDatabase,
168}
169
170impl<'a> ThisTypeMarkerExtractor<'a> {
171 fn new(db: &'a dyn TypeDatabase) -> Self {
172 Self { db }
173 }
174
175 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
176 self.visit_type(self.db, type_id)
177 }
178
179 fn is_this_type_application(&self, app_id: u32) -> bool {
181 let app = self.db.type_application(TypeApplicationId(app_id));
182
183 if let Some(TypeData::TypeParameter(tp)) = self.db.lookup(app.base) {
189 let name = self.db.resolve_atom_ref(tp.name);
190 return name.as_ref() == "ThisType";
191 }
192
193 if let Some(TypeData::Lazy(_def_id)) = self.db.lookup(app.base) {
198 return false;
201 }
202
203 false
204 }
205}
206
207impl<'a> TypeVisitor for ThisTypeMarkerExtractor<'a> {
208 type Output = Option<TypeId>;
209
210 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
211 None
212 }
213
214 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
215 None
216 }
217
218 fn visit_application(&mut self, app_id: u32) -> Self::Output {
219 if self.is_this_type_application(app_id) {
220 let app = self.db.type_application(TypeApplicationId(app_id));
221 app.args.first().copied()
223 } else {
224 let app = self.db.type_application(TypeApplicationId(app_id));
226 let base_result = self.visit_type(self.db, app.base);
227
228 let arg_results: Vec<_> = app
230 .args
231 .iter()
232 .filter_map(|&arg_id| self.visit_type(self.db, arg_id))
233 .collect();
234
235 if let Some(result) = base_result {
238 Some(result)
239 } else if let Some(&first) = arg_results.first() {
240 Some(first)
241 } else {
242 None
243 }
244 }
245 }
246
247 fn visit_intersection(&mut self, list_id: u32) -> Self::Output {
248 let members = self.db.type_list(TypeListId(list_id));
249
250 let this_types: Vec<TypeId> = members
252 .iter()
253 .filter_map(|&member_id| self.visit_type(self.db, member_id))
254 .collect();
255
256 if this_types.is_empty() {
257 None
258 } else if this_types.len() == 1 {
259 Some(this_types[0])
260 } else {
261 Some(self.db.intersection(this_types))
264 }
265 }
266
267 fn visit_union(&mut self, list_id: u32) -> Self::Output {
268 let members = self.db.type_list(TypeListId(list_id));
271
272 members
279 .iter()
280 .find_map(|&member_id| self.visit_type(self.db, member_id))
281 }
282
283 fn default_output() -> Self::Output {
284 None
285 }
286}
287
288struct ArrayElementExtractor<'a> {
290 db: &'a dyn TypeDatabase,
291}
292
293impl<'a> ArrayElementExtractor<'a> {
294 fn new(db: &'a dyn TypeDatabase) -> Self {
295 Self { db }
296 }
297
298 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
299 self.visit_type(self.db, type_id)
300 }
301}
302
303impl<'a> TypeVisitor for ArrayElementExtractor<'a> {
304 type Output = Option<TypeId>;
305
306 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
307 None
308 }
309
310 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
311 None
312 }
313
314 fn visit_array(&mut self, elem_type: TypeId) -> Self::Output {
315 Some(elem_type)
316 }
317
318 fn visit_object(&mut self, shape_id: u32) -> Self::Output {
319 let shape = self.db.object_shape(ObjectShapeId(shape_id));
320 if let Some(ref idx) = shape.number_index {
321 return Some(idx.value_type);
322 }
323 if let Some(ref idx) = shape.string_index {
324 return Some(idx.value_type);
325 }
326 None
327 }
328
329 fn visit_object_with_index(&mut self, shape_id: u32) -> Self::Output {
330 self.visit_object(shape_id)
331 }
332
333 fn visit_tuple(&mut self, elements_id: u32) -> Self::Output {
334 let elements = self.db.tuple_list(TupleListId(elements_id));
335 if elements.is_empty() {
336 None
337 } else {
338 let types: Vec<TypeId> = elements.iter().map(|e| e.type_id).collect();
339 Some(self.db.union(types))
340 }
341 }
342
343 fn default_output() -> Self::Output {
344 None
345 }
346}
347
348struct TupleElementExtractor<'a> {
350 db: &'a dyn TypeDatabase,
351 index: usize,
352}
353
354impl<'a> TupleElementExtractor<'a> {
355 fn new(db: &'a dyn TypeDatabase, index: usize) -> Self {
356 Self { db, index }
357 }
358
359 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
360 self.visit_type(self.db, type_id)
361 }
362}
363
364impl<'a> TypeVisitor for TupleElementExtractor<'a> {
365 type Output = Option<TypeId>;
366
367 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
368 None
369 }
370
371 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
372 None
373 }
374
375 fn visit_tuple(&mut self, elements_id: u32) -> Self::Output {
376 let elements = self.db.tuple_list(TupleListId(elements_id));
377 if self.index < elements.len() {
378 Some(elements[self.index].type_id)
379 } else if let Some(last) = elements.last() {
380 last.rest.then_some(last.type_id)
381 } else {
382 None
383 }
384 }
385
386 fn visit_array(&mut self, elem_type: TypeId) -> Self::Output {
387 Some(elem_type)
388 }
389
390 fn visit_object(&mut self, shape_id: u32) -> Self::Output {
391 let shape = self.db.object_shape(ObjectShapeId(shape_id));
392 if let Some(ref idx) = shape.number_index {
393 return Some(idx.value_type);
394 }
395 if let Some(ref idx) = shape.string_index {
396 return Some(idx.value_type);
397 }
398 None
399 }
400
401 fn visit_object_with_index(&mut self, shape_id: u32) -> Self::Output {
402 self.visit_object(shape_id)
403 }
404
405 fn visit_union(&mut self, list_id: u32) -> Self::Output {
406 let members = self.db.type_list(TypeListId(list_id));
409 let types: Vec<TypeId> = members
410 .iter()
411 .filter_map(|&member| {
412 let mut extractor = TupleElementExtractor::new(self.db, self.index);
413 extractor.extract(member)
414 })
415 .collect();
416 collect_single_or_union(self.db, types)
417 }
418
419 fn visit_intersection(&mut self, list_id: u32) -> Self::Output {
420 let members = self.db.type_list(TypeListId(list_id));
422 for &member in members.iter() {
423 let mut extractor = TupleElementExtractor::new(self.db, self.index);
424 if let Some(ty) = extractor.extract(member) {
425 return Some(ty);
426 }
427 }
428 None
429 }
430
431 fn default_output() -> Self::Output {
432 None
433 }
434}
435
436struct PropertyExtractor<'a> {
438 db: &'a dyn TypeDatabase,
439 name: String,
440}
441
442impl<'a> PropertyExtractor<'a> {
443 fn new(db: &'a dyn TypeDatabase, name: String) -> Self {
444 Self { db, name }
445 }
446
447 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
448 self.visit_type(self.db, type_id)
449 }
450}
451
452impl<'a> TypeVisitor for PropertyExtractor<'a> {
453 type Output = Option<TypeId>;
454
455 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
456 None
457 }
458
459 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
460 None
461 }
462
463 fn visit_object(&mut self, shape_id: u32) -> Self::Output {
464 let shape = self.db.object_shape(ObjectShapeId(shape_id));
465 for prop in &shape.properties {
466 if self.db.resolve_atom_ref(prop.name).as_ref() == self.name {
467 return Some(prop.type_id);
468 }
469 }
470 if self.name.parse::<f64>().is_ok()
475 && let Some(ref idx) = shape.number_index
476 {
477 return Some(idx.value_type);
478 }
479 if let Some(ref idx) = shape.string_index {
480 return Some(idx.value_type);
481 }
482 None
483 }
484
485 fn visit_object_with_index(&mut self, shape_id: u32) -> Self::Output {
486 if let Some(ty) = self.visit_object(shape_id) {
488 return Some(ty);
489 }
490 let shape = self.db.object_shape(ObjectShapeId(shape_id));
491 if self.name.parse::<f64>().is_ok()
493 && let Some(ref idx) = shape.number_index
494 {
495 return Some(idx.value_type);
496 }
497 if let Some(ref idx) = shape.string_index {
499 return Some(idx.value_type);
500 }
501 None
502 }
503
504 fn visit_lazy(&mut self, def_id: u32) -> Self::Output {
505 let resolved = crate::evaluate::evaluate_type(self.db, TypeId(def_id));
506 if resolved != TypeId(def_id) {
507 self.visit_type(self.db, resolved)
508 } else {
509 None
510 }
511 }
512
513 fn visit_union(&mut self, list_id: u32) -> Self::Output {
514 let members = self.db.type_list(TypeListId(list_id));
518 let types: Vec<TypeId> = members
519 .iter()
520 .filter_map(|&member| {
521 let mut extractor = PropertyExtractor::new(self.db, self.name.clone());
522 extractor.extract(member)
523 })
524 .collect();
525 collect_single_or_union(self.db, types)
526 }
527
528 fn visit_intersection(&mut self, list_id: u32) -> Self::Output {
529 let members = self.db.type_list(TypeListId(list_id));
530 for &member in members.iter() {
531 let mut extractor = PropertyExtractor::new(self.db, self.name.clone());
532 if let Some(ty) = extractor.extract(member) {
533 return Some(ty);
534 }
535 }
536 None
537 }
538
539 fn default_output() -> Self::Output {
540 None
541 }
542}
543
544fn extract_param_type_at(
546 db: &dyn TypeDatabase,
547 params: &[ParamInfo],
548 index: usize,
549) -> Option<TypeId> {
550 let rest_param = params.last().filter(|p| p.rest);
551 let rest_start = if rest_param.is_some() {
552 params.len().saturating_sub(1)
553 } else {
554 params.len()
555 };
556
557 if index < rest_start {
559 return Some(params[index].type_id);
560 }
561
562 if let Some(last_param) = rest_param {
564 let rest_index = index - rest_start;
566 if let Some(TypeData::Array(elem)) = db.lookup(last_param.type_id) {
567 return Some(elem);
568 }
569 if let Some(TypeData::Tuple(elements)) = db.lookup(last_param.type_id) {
570 let elements = db.tuple_list(elements);
571 if rest_index < elements.len() {
572 return Some(elements[rest_index].type_id);
573 } else if let Some(last_elem) = elements.last()
574 && last_elem.rest
575 {
576 return Some(last_elem.type_id);
577 }
578 } else if let Some(TypeData::TypeParameter(param_info)) = db.lookup(last_param.type_id) {
581 if let Some(constraint) = param_info.constraint {
582 let mut mock_params = params.to_vec();
583 mock_params.last_mut().unwrap().type_id = constraint;
584 return extract_param_type_at(db, &mock_params, index);
585 }
586 } else if let Some(TypeData::Intersection(members)) = db.lookup(last_param.type_id) {
587 let members = db.type_list(members);
588 for &m in members.iter() {
589 let mut mock_params = params.to_vec();
590 mock_params.last_mut().unwrap().type_id = m;
591 if let Some(param_type) = extract_param_type_at(db, &mock_params, index) {
592 if !matches!(
594 db.lookup(param_type),
595 Some(TypeData::TypeParameter(_) | TypeData::Intersection(_))
596 ) {
597 return Some(param_type);
598 }
599 }
600 }
601 } else if let Some(TypeData::Application(_app_id)) = db.lookup(last_param.type_id) {
603 let evaluated = crate::evaluate::evaluate_type(db, last_param.type_id);
604 if evaluated != last_param.type_id {
605 let mut mock_params = params.to_vec();
606 mock_params.last_mut().unwrap().type_id = evaluated;
607 return extract_param_type_at(db, &mock_params, index);
608 }
609 }
610
611 if let Some(constraint) =
613 crate::type_queries::get_type_parameter_constraint(db, last_param.type_id)
614 {
615 let mut mock_params = params.to_vec();
616 mock_params.last_mut().unwrap().type_id = constraint;
617 if let Some(param_type) = extract_param_type_at(db, &mock_params, index) {
618 if param_type != constraint {
620 return Some(param_type);
621 }
622 }
623 }
624
625 return Some(last_param.type_id);
626 }
627
628 (index < params.len()).then(|| params[index].type_id)
630}
631
632struct ParameterExtractor<'a> {
634 db: &'a dyn TypeDatabase,
635 index: usize,
636 no_implicit_any: bool,
637}
638
639impl<'a> ParameterExtractor<'a> {
640 fn new(db: &'a dyn TypeDatabase, index: usize, no_implicit_any: bool) -> Self {
641 Self {
642 db,
643 index,
644 no_implicit_any,
645 }
646 }
647
648 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
649 self.visit_type(self.db, type_id)
650 }
651}
652
653impl<'a> TypeVisitor for ParameterExtractor<'a> {
654 type Output = Option<TypeId>;
655
656 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
657 None
658 }
659
660 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
661 None
662 }
663
664 fn visit_function(&mut self, shape_id: u32) -> Self::Output {
665 let shape = self.db.function_shape(FunctionShapeId(shape_id));
666 extract_param_type_at(self.db, &shape.params, self.index)
667 }
668
669 fn visit_callable(&mut self, shape_id: u32) -> Self::Output {
670 let shape = self.db.callable_shape(CallableShapeId(shape_id));
671 let param_types: Vec<TypeId> = shape
673 .call_signatures
674 .iter()
675 .filter_map(|sig| extract_param_type_at(self.db, &sig.params, self.index))
676 .collect();
677
678 if param_types.is_empty() {
679 None
680 } else if param_types.len() == 1 {
681 Some(param_types[0])
682 } else {
683 self.no_implicit_any.then(|| self.db.union(param_types))
687 }
688 }
689
690 fn visit_union(&mut self, list_id: u32) -> Self::Output {
691 let members = self.db.type_list(TypeListId(list_id));
695 let types: Vec<TypeId> = members
696 .iter()
697 .filter_map(|&member| {
698 let mut extractor =
699 ParameterExtractor::new(self.db, self.index, self.no_implicit_any);
700 extractor.extract(member)
701 })
702 .collect();
703 collect_single_or_union(self.db, types)
704 }
705
706 fn visit_intersection(&mut self, list_id: u32) -> Self::Output {
707 let members = self.db.type_list(TypeListId(list_id));
709 for &member in members.iter() {
710 let mut extractor = ParameterExtractor::new(self.db, self.index, self.no_implicit_any);
711 if let Some(ty) = extractor.extract(member) {
712 return Some(ty);
713 }
714 }
715 None
716 }
717
718 fn default_output() -> Self::Output {
719 None
720 }
721}
722
723struct ParameterForCallExtractor<'a> {
726 db: &'a dyn TypeDatabase,
727 index: usize,
728 arg_count: usize,
729}
730
731impl<'a> ParameterForCallExtractor<'a> {
732 fn new(db: &'a dyn TypeDatabase, index: usize, arg_count: usize) -> Self {
733 Self {
734 db,
735 index,
736 arg_count,
737 }
738 }
739
740 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
741 self.visit_type(self.db, type_id)
742 }
743
744 fn signature_accepts_arg_count(&self, params: &[ParamInfo], arg_count: usize) -> bool {
745 let required_count = params.iter().filter(|p| !p.optional).count();
747
748 let has_rest = params.iter().any(|p| p.rest);
750
751 if has_rest {
752 arg_count >= required_count
754 } else {
755 arg_count >= required_count && arg_count <= params.len()
757 }
758 }
759}
760
761impl<'a> TypeVisitor for ParameterForCallExtractor<'a> {
762 type Output = Option<TypeId>;
763
764 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
765 None
766 }
767
768 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
769 None
770 }
771
772 fn visit_function(&mut self, shape_id: u32) -> Self::Output {
773 let shape = self.db.function_shape(FunctionShapeId(shape_id));
774
775 if !self.signature_accepts_arg_count(&shape.params, self.arg_count) {
776 return None;
777 }
778
779 extract_param_type_at(self.db, &shape.params, self.index)
780 }
781
782 fn visit_callable(&mut self, shape_id: u32) -> Self::Output {
783 let shape = self.db.callable_shape(CallableShapeId(shape_id));
784
785 let mut matched = false;
786 let mut param_types: Vec<TypeId> = Vec::new();
787
788 for sig in &shape.call_signatures {
789 if self.signature_accepts_arg_count(&sig.params, self.arg_count) {
790 matched = true;
791 if let Some(param_type) = extract_param_type_at(self.db, &sig.params, self.index) {
792 param_types.push(param_type);
793 }
794 }
795 }
796
797 if param_types.is_empty() && !matched {
798 param_types = shape
799 .call_signatures
800 .iter()
801 .filter_map(|sig| extract_param_type_at(self.db, &sig.params, self.index))
802 .collect();
803 }
804
805 if param_types.is_empty() {
811 matched = false;
812 for sig in &shape.construct_signatures {
813 if !sig.type_params.is_empty() {
814 continue;
815 }
816 if self.signature_accepts_arg_count(&sig.params, self.arg_count) {
817 matched = true;
818 if let Some(param_type) =
819 extract_param_type_at(self.db, &sig.params, self.index)
820 {
821 param_types.push(param_type);
822 }
823 }
824 }
825 if param_types.is_empty() && !matched {
826 param_types = shape
827 .construct_signatures
828 .iter()
829 .filter(|sig| sig.type_params.is_empty())
830 .filter_map(|sig| extract_param_type_at(self.db, &sig.params, self.index))
831 .collect();
832 }
833 }
834
835 collect_single_or_union(self.db, param_types)
836 }
837
838 fn visit_union(&mut self, list_id: u32) -> Self::Output {
839 let members = self.db.type_list(TypeListId(list_id));
841 let types: Vec<TypeId> = members
842 .iter()
843 .filter_map(|&member| {
844 let mut extractor =
845 ParameterForCallExtractor::new(self.db, self.index, self.arg_count);
846 extractor.extract(member)
847 })
848 .collect();
849 collect_single_or_union(self.db, types)
850 }
851
852 fn default_output() -> Self::Output {
853 None
854 }
855}
856
857struct ApplicationArgExtractor<'a> {
862 db: &'a dyn TypeDatabase,
863 arg_index: usize,
864}
865
866impl<'a> ApplicationArgExtractor<'a> {
867 fn new(db: &'a dyn TypeDatabase, arg_index: usize) -> Self {
868 Self { db, arg_index }
869 }
870
871 fn extract(&mut self, type_id: TypeId) -> Option<TypeId> {
872 self.visit_type(self.db, type_id)
873 }
874}
875
876impl<'a> TypeVisitor for ApplicationArgExtractor<'a> {
877 type Output = Option<TypeId>;
878
879 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
880 None
881 }
882
883 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
884 None
885 }
886
887 fn visit_application(&mut self, app_id: u32) -> Self::Output {
888 let app = self.db.type_application(TypeApplicationId(app_id));
889 app.args.get(self.arg_index).copied()
890 }
891
892 fn default_output() -> Self::Output {
893 None
894 }
895}
896
897pub struct ContextualTypeContext<'a> {
900 interner: &'a dyn TypeDatabase,
901 expected: Option<TypeId>,
903 no_implicit_any: bool,
905}
906
907impl<'a> ContextualTypeContext<'a> {
908 pub fn new(interner: &'a dyn TypeDatabase) -> Self {
911 ContextualTypeContext {
912 interner,
913 expected: None,
914 no_implicit_any: false,
915 }
916 }
917
918 pub fn with_expected(interner: &'a dyn TypeDatabase, expected: TypeId) -> Self {
921 ContextualTypeContext {
922 interner,
923 expected: Some(expected),
924 no_implicit_any: false,
925 }
926 }
927
928 pub fn with_expected_and_options(
930 interner: &'a dyn TypeDatabase,
931 expected: TypeId,
932 no_implicit_any: bool,
933 ) -> Self {
934 ContextualTypeContext {
935 interner,
936 expected: Some(expected),
937 no_implicit_any,
938 }
939 }
940
941 pub const fn expected(&self) -> Option<TypeId> {
943 self.expected
944 }
945
946 pub const fn has_context(&self) -> bool {
948 self.expected.is_some()
949 }
950
951 pub fn get_parameter_type(&self, index: usize) -> Option<TypeId> {
959 let expected = self.expected?;
960
961 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
963 let members = self.interner.type_list(members);
964 let param_types: Vec<TypeId> = members
965 .iter()
966 .filter_map(|&m| {
967 let ctx = ContextualTypeContext::with_expected_and_options(
968 self.interner,
969 m,
970 self.no_implicit_any,
971 );
972 ctx.get_parameter_type(index)
973 })
974 .collect();
975
976 return collect_single_or_union(self.interner, param_types);
977 }
978
979 if let Some(TypeData::Application(app_id)) = self.interner.lookup(expected) {
981 let app = self.interner.type_application(app_id);
982 let ctx = ContextualTypeContext::with_expected_and_options(
983 self.interner,
984 app.base,
985 self.no_implicit_any,
986 );
987 return ctx.get_parameter_type(index);
988 }
989
990 if let Some(TypeData::Intersection(members)) = self.interner.lookup(expected) {
992 let members = self.interner.type_list(members);
993 for &m in members.iter() {
994 let ctx = ContextualTypeContext::with_expected_and_options(
995 self.interner,
996 m,
997 self.no_implicit_any,
998 );
999 if let Some(param_type) = ctx.get_parameter_type(index) {
1000 return Some(param_type);
1001 }
1002 }
1003 return None;
1004 }
1005
1006 if let Some(TypeData::Mapped(_) | TypeData::Conditional(_) | TypeData::Lazy(_)) =
1008 self.interner.lookup(expected)
1009 {
1010 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1011 if evaluated != expected {
1012 let ctx = ContextualTypeContext::with_expected_and_options(
1013 self.interner,
1014 evaluated,
1015 self.no_implicit_any,
1016 );
1017 return ctx.get_parameter_type(index);
1018 }
1019 }
1020
1021 let mut extractor = ParameterExtractor::new(self.interner, index, self.no_implicit_any);
1023 extractor.extract(expected)
1024 }
1025
1026 pub fn get_parameter_type_for_call(&self, index: usize, arg_count: usize) -> Option<TypeId> {
1028 let expected = self.expected?;
1029
1030 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1032 let members = self.interner.type_list(members);
1033 let param_types: Vec<TypeId> = members
1034 .iter()
1035 .filter_map(|&m| {
1036 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1037 ctx.get_parameter_type_for_call(index, arg_count)
1038 })
1039 .collect();
1040
1041 return collect_single_or_union(self.interner, param_types);
1042 }
1043
1044 if let Some(TypeData::Application(app_id)) = self.interner.lookup(expected) {
1046 let app = self.interner.type_application(app_id);
1047 let ctx = ContextualTypeContext::with_expected(self.interner, app.base);
1048 return ctx.get_parameter_type_for_call(index, arg_count);
1049 }
1050
1051 if let Some(TypeData::Intersection(members)) = self.interner.lookup(expected) {
1053 let members = self.interner.type_list(members);
1054 for &m in members.iter() {
1055 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1056 if let Some(param_type) = ctx.get_parameter_type_for_call(index, arg_count) {
1057 return Some(param_type);
1058 }
1059 }
1060 return None;
1061 }
1062
1063 let mut extractor = ParameterForCallExtractor::new(self.interner, index, arg_count);
1065 extractor.extract(expected)
1066 }
1067
1068 pub fn get_this_type(&self) -> Option<TypeId> {
1070 let expected = self.expected?;
1071
1072 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1074 let members = self.interner.type_list(members);
1075 let this_types: Vec<TypeId> = members
1076 .iter()
1077 .filter_map(|&m| {
1078 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1079 ctx.get_this_type()
1080 })
1081 .collect();
1082
1083 return collect_single_or_union(self.interner, this_types);
1084 }
1085
1086 if let Some(TypeData::Application(app_id)) = self.interner.lookup(expected) {
1088 let app = self.interner.type_application(app_id);
1089 let ctx = ContextualTypeContext::with_expected(self.interner, app.base);
1090 return ctx.get_this_type();
1091 }
1092
1093 let mut extractor = ThisTypeExtractor::new(self.interner);
1095 extractor.extract(expected)
1096 }
1097
1098 pub fn get_this_type_from_marker(&self) -> Option<TypeId> {
1115 let expected = self.expected?;
1116 let mut extractor = ThisTypeMarkerExtractor::new(self.interner);
1117 extractor.extract(expected)
1118 }
1119
1120 pub fn get_return_type(&self) -> Option<TypeId> {
1122 let expected = self.expected?;
1123
1124 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1126 let members = self.interner.type_list(members);
1127 let return_types: Vec<TypeId> = members
1128 .iter()
1129 .filter_map(|&m| {
1130 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1131 ctx.get_return_type()
1132 })
1133 .collect();
1134
1135 return collect_single_or_union(self.interner, return_types);
1136 }
1137
1138 if let Some(TypeData::Application(app_id)) = self.interner.lookup(expected) {
1140 let app = self.interner.type_application(app_id);
1141 let ctx = ContextualTypeContext::with_expected(self.interner, app.base);
1142 return ctx.get_return_type();
1143 }
1144
1145 if let Some(TypeData::Lazy(_) | TypeData::Mapped(_) | TypeData::Conditional(_)) =
1147 self.interner.lookup(expected)
1148 {
1149 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1150 if evaluated != expected {
1151 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1152 return ctx.get_return_type();
1153 }
1154 }
1155
1156 let mut extractor = ReturnTypeExtractor::new(self.interner);
1158 extractor.extract(expected)
1159 }
1160
1161 pub fn get_array_element_type(&self) -> Option<TypeId> {
1168 let expected = self.expected?;
1169
1170 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1172 let members = self.interner.type_list(members);
1173 let elem_types: Vec<TypeId> = members
1174 .iter()
1175 .filter_map(|&m| {
1176 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1177 ctx.get_array_element_type()
1178 })
1179 .collect();
1180 return collect_single_or_union(self.interner, elem_types);
1181 }
1182
1183 if let Some(TypeData::Application(_)) = self.interner.lookup(expected) {
1185 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1186 if evaluated != expected {
1187 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1188 return ctx.get_array_element_type();
1189 }
1190 }
1191
1192 if let Some(TypeData::Mapped(_) | TypeData::Conditional(_) | TypeData::Lazy(_)) =
1194 self.interner.lookup(expected)
1195 {
1196 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1197 if evaluated != expected {
1198 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1199 return ctx.get_array_element_type();
1200 }
1201 }
1202
1203 if let Some(constraint) =
1205 crate::type_queries::get_type_parameter_constraint(self.interner, expected)
1206 {
1207 let ctx = ContextualTypeContext::with_expected(self.interner, constraint);
1208 return ctx.get_array_element_type();
1209 }
1210
1211 if let Some(TypeData::Intersection(members)) = self.interner.lookup(expected) {
1213 let members = self.interner.type_list(members);
1214 for &m in members.iter() {
1215 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1216 if let Some(elem_type) = ctx.get_array_element_type() {
1217 return Some(elem_type);
1218 }
1219 }
1220 return None;
1221 }
1222
1223 let mut extractor = ArrayElementExtractor::new(self.interner);
1224 extractor.extract(expected)
1225 }
1226
1227 pub fn get_tuple_element_type(&self, index: usize) -> Option<TypeId> {
1229 let expected = self.expected?;
1230
1231 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1233 let members = self.interner.type_list(members);
1234 let elem_types: Vec<TypeId> = members
1235 .iter()
1236 .filter_map(|&m| {
1237 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1238 ctx.get_tuple_element_type(index)
1239 })
1240 .collect();
1241 return collect_single_or_union(self.interner, elem_types);
1242 }
1243
1244 if let Some(TypeData::Application(_)) = self.interner.lookup(expected) {
1246 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1247 if evaluated != expected {
1248 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1249 return ctx.get_tuple_element_type(index);
1250 }
1251 }
1252
1253 if let Some(constraint) =
1255 crate::type_queries::get_type_parameter_constraint(self.interner, expected)
1256 {
1257 let ctx = ContextualTypeContext::with_expected(self.interner, constraint);
1258 return ctx.get_tuple_element_type(index);
1259 }
1260
1261 if let Some(TypeData::Mapped(_) | TypeData::Conditional(_) | TypeData::Lazy(_)) =
1263 self.interner.lookup(expected)
1264 {
1265 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1266 if evaluated != expected {
1267 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1268 return ctx.get_tuple_element_type(index);
1269 }
1270 }
1271
1272 let mut extractor = TupleElementExtractor::new(self.interner, index);
1273 extractor.extract(expected)
1274 }
1275
1276 pub fn get_property_type(&self, name: &str) -> Option<TypeId> {
1283 let expected = self.expected?;
1284
1285 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1287 let members = self.interner.type_list(members);
1288 let prop_types: Vec<TypeId> = members
1289 .iter()
1290 .filter_map(|&m| {
1291 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1292 ctx.get_property_type(name)
1293 })
1294 .collect();
1295
1296 return if prop_types.is_empty() {
1297 None
1298 } else if prop_types.len() == 1 {
1299 Some(prop_types[0])
1300 } else {
1301 Some(self.interner.union_preserve_members(prop_types))
1306 };
1307 }
1308
1309 match self.interner.lookup(expected) {
1313 Some(TypeData::Mapped(mapped_id)) => {
1314 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1316 if evaluated != expected {
1317 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1318 return ctx.get_property_type(name);
1319 }
1320 let mapped = self.interner.mapped_type(mapped_id);
1327 if mapped.template != TypeId::ANY
1328 && mapped.template != TypeId::ERROR
1329 && mapped.template != TypeId::NEVER
1330 && !crate::visitor::contains_type_matching(
1331 self.interner,
1332 mapped.template,
1333 |key| matches!(key, TypeData::BoundParameter(_)),
1334 )
1335 {
1336 return Some(mapped.template);
1337 }
1338 if let Some(TypeData::KeyOf(operand)) = self.interner.lookup(mapped.constraint) {
1341 let resolved_operand = crate::evaluate::evaluate_type(self.interner, operand);
1343 if let Some(constraint) = crate::type_queries::get_type_parameter_constraint(
1344 self.interner,
1345 resolved_operand,
1346 ) {
1347 let ctx = ContextualTypeContext::with_expected(self.interner, constraint);
1348 return ctx.get_property_type(name);
1349 }
1350 if let Some(constraint) =
1352 crate::type_queries::get_type_parameter_constraint(self.interner, operand)
1353 {
1354 let ctx = ContextualTypeContext::with_expected(self.interner, constraint);
1355 return ctx.get_property_type(name);
1356 }
1357 }
1358 }
1359 Some(TypeData::Application(app_id)) => {
1360 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1361 if evaluated != expected {
1362 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1363 return ctx.get_property_type(name);
1364 }
1365 let app = self.interner.type_application(app_id);
1370 if !app.args.is_empty() {
1371 let ctx = ContextualTypeContext::with_expected(self.interner, app.args[0]);
1372 if let Some(prop) = ctx.get_property_type(name) {
1373 return Some(prop);
1374 }
1375 }
1376 }
1377 Some(TypeData::Conditional(_) | TypeData::Lazy(_)) => {
1378 let evaluated = crate::evaluate::evaluate_type(self.interner, expected);
1379 if evaluated != expected {
1380 let ctx = ContextualTypeContext::with_expected(self.interner, evaluated);
1381 return ctx.get_property_type(name);
1382 }
1383 }
1384 _ => {}
1385 }
1386
1387 if let Some(constraint) =
1391 crate::type_queries::get_type_parameter_constraint(self.interner, expected)
1392 {
1393 let ctx = ContextualTypeContext::with_expected(self.interner, constraint);
1394 return ctx.get_property_type(name);
1395 }
1396
1397 let mut extractor = PropertyExtractor::new(self.interner, name.to_string());
1399 extractor.extract(expected)
1400 }
1401
1402 pub fn for_property(&self, name: &str) -> Self {
1405 match self.get_property_type(name) {
1406 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1407 None => ContextualTypeContext::new(self.interner),
1408 }
1409 }
1410
1411 pub fn for_array_element(&self) -> Self {
1413 match self.get_array_element_type() {
1414 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1415 None => ContextualTypeContext::new(self.interner),
1416 }
1417 }
1418
1419 pub fn for_tuple_element(&self, index: usize) -> Self {
1421 match self.get_tuple_element_type(index) {
1422 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1423 None => ContextualTypeContext::new(self.interner),
1424 }
1425 }
1426
1427 pub fn for_parameter(&self, index: usize) -> Self {
1429 match self.get_parameter_type(index) {
1430 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1431 None => ContextualTypeContext::new(self.interner),
1432 }
1433 }
1434
1435 pub fn for_return(&self) -> Self {
1437 match self.get_return_type() {
1438 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1439 None => ContextualTypeContext::new(self.interner),
1440 }
1441 }
1442
1443 pub fn get_generator_yield_type(&self) -> Option<TypeId> {
1455 let expected = self.expected?;
1456
1457 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1459 let members = self.interner.type_list(members);
1460 let yield_types: Vec<TypeId> = members
1461 .iter()
1462 .filter_map(|&m| {
1463 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1464 ctx.get_generator_yield_type()
1465 })
1466 .collect();
1467
1468 return collect_single_or_union(self.interner, yield_types);
1469 }
1470
1471 let mut extractor = ApplicationArgExtractor::new(self.interner, 0);
1473 extractor.extract(expected)
1474 }
1475
1476 pub fn get_generator_return_type(&self) -> Option<TypeId> {
1480 let expected = self.expected?;
1481
1482 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1484 let members = self.interner.type_list(members);
1485 let return_types: Vec<TypeId> = members
1486 .iter()
1487 .filter_map(|&m| {
1488 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1489 ctx.get_generator_return_type()
1490 })
1491 .collect();
1492
1493 return collect_single_or_union(self.interner, return_types);
1494 }
1495
1496 let mut extractor = ApplicationArgExtractor::new(self.interner, 1);
1498 extractor.extract(expected)
1499 }
1500
1501 pub fn get_generator_next_type(&self) -> Option<TypeId> {
1506 let expected = self.expected?;
1507
1508 if let Some(TypeData::Union(members)) = self.interner.lookup(expected) {
1510 let members = self.interner.type_list(members);
1511 let next_types: Vec<TypeId> = members
1512 .iter()
1513 .filter_map(|&m| {
1514 let ctx = ContextualTypeContext::with_expected(self.interner, m);
1515 ctx.get_generator_next_type()
1516 })
1517 .collect();
1518
1519 return collect_single_or_union(self.interner, next_types);
1520 }
1521
1522 let mut extractor = ApplicationArgExtractor::new(self.interner, 2);
1524 extractor.extract(expected)
1525 }
1526
1527 pub fn for_yield(&self) -> Self {
1529 match self.get_generator_yield_type() {
1530 Some(ty) => ContextualTypeContext::with_expected(self.interner, ty),
1531 None => ContextualTypeContext::new(self.interner),
1532 }
1533 }
1534}
1535
1536pub fn apply_contextual_type(
1544 interner: &dyn TypeDatabase,
1545 expr_type: TypeId,
1546 contextual_type: Option<TypeId>,
1547) -> TypeId {
1548 let ctx_type = match contextual_type {
1549 Some(t) => t,
1550 None => return expr_type,
1551 };
1552
1553 if expr_type.is_any_or_unknown() || expr_type.is_error() {
1555 return ctx_type;
1556 }
1557
1558 if expr_type == ctx_type {
1560 return expr_type;
1561 }
1562
1563 if let Some(expr_key) = interner.lookup(expr_type) {
1566 if matches!(expr_key, TypeData::Literal(_))
1568 && let Some(ctx_key) = interner.lookup(ctx_type)
1569 && matches!(ctx_key, TypeData::Union(_))
1570 {
1571 return expr_type;
1573 }
1574 }
1575
1576 let mut checker = crate::subtype::SubtypeChecker::new(interner);
1578
1579 if let Some(TypeData::Union(members)) = interner.lookup(ctx_type) {
1581 let members = interner.type_list(members);
1582 for &member in members.iter() {
1584 if member == expr_type {
1585 return expr_type;
1586 }
1587 }
1588 for &member in members.iter() {
1590 checker.reset();
1591 if checker.is_subtype_of(expr_type, member) {
1592 return expr_type;
1593 }
1594 }
1595 }
1596
1597 checker.reset();
1599 if checker.is_subtype_of(expr_type, ctx_type) {
1600 return expr_type;
1601 }
1602
1603 let is_function_type = matches!(
1609 interner.lookup(expr_type),
1610 Some(TypeData::Function(_) | TypeData::Object(_))
1611 );
1612 if !is_function_type {
1613 checker.reset();
1614 if checker.is_subtype_of(ctx_type, expr_type) {
1615 return ctx_type;
1616 }
1617 }
1618
1619 expr_type
1622}
1623
1624#[cfg(test)]
1625#[path = "../tests/contextual_tests.rs"]
1626mod tests;