1use crate::def::DefId;
42use crate::types::{IntrinsicKind, StringIntrinsicKind, TupleElement, TypeParamInfo};
43use crate::{LiteralValue, SymbolRef, TypeData, TypeDatabase, TypeId};
44use rustc_hash::FxHashSet;
45
46pub use super::visitor_extract::*;
48
49pub use super::visitor_predicates::*;
51
52pub trait TypeVisitor: Sized {
62 type Output;
64
65 fn visit_intrinsic(&mut self, kind: IntrinsicKind) -> Self::Output;
71
72 fn visit_literal(&mut self, value: &LiteralValue) -> Self::Output;
74
75 fn visit_object(&mut self, _shape_id: u32) -> Self::Output {
81 Self::default_output()
82 }
83
84 fn visit_object_with_index(&mut self, _shape_id: u32) -> Self::Output {
86 Self::default_output()
87 }
88
89 fn visit_union(&mut self, _list_id: u32) -> Self::Output {
91 Self::default_output()
92 }
93
94 fn visit_intersection(&mut self, _list_id: u32) -> Self::Output {
96 Self::default_output()
97 }
98
99 fn visit_array(&mut self, _element_type: TypeId) -> Self::Output {
101 Self::default_output()
102 }
103
104 fn visit_tuple(&mut self, _list_id: u32) -> Self::Output {
106 Self::default_output()
107 }
108
109 fn visit_function(&mut self, _shape_id: u32) -> Self::Output {
111 Self::default_output()
112 }
113
114 fn visit_callable(&mut self, _shape_id: u32) -> Self::Output {
116 Self::default_output()
117 }
118
119 fn visit_type_parameter(&mut self, _param_info: &TypeParamInfo) -> Self::Output {
121 Self::default_output()
122 }
123
124 fn visit_bound_parameter(&mut self, _de_bruijn_index: u32) -> Self::Output {
130 Self::default_output()
131 }
132
133 fn visit_ref(&mut self, _symbol_ref: u32) -> Self::Output {
135 Self::default_output()
136 }
137
138 fn visit_enum(&mut self, _def_id: u32, _member_type: TypeId) -> Self::Output {
140 Self::default_output()
141 }
142
143 fn visit_lazy(&mut self, _def_id: u32) -> Self::Output {
145 Self::default_output()
146 }
147
148 fn visit_recursive(&mut self, _de_bruijn_index: u32) -> Self::Output {
153 Self::default_output()
154 }
155
156 fn visit_application(&mut self, _app_id: u32) -> Self::Output {
158 Self::default_output()
159 }
160
161 fn visit_conditional(&mut self, _cond_id: u32) -> Self::Output {
163 Self::default_output()
164 }
165
166 fn visit_mapped(&mut self, _mapped_id: u32) -> Self::Output {
168 Self::default_output()
169 }
170
171 fn visit_index_access(&mut self, _object_type: TypeId, _key_type: TypeId) -> Self::Output {
173 Self::default_output()
174 }
175
176 fn visit_template_literal(&mut self, _template_id: u32) -> Self::Output {
178 Self::default_output()
179 }
180
181 fn visit_type_query(&mut self, _symbol_ref: u32) -> Self::Output {
183 Self::default_output()
184 }
185
186 fn visit_keyof(&mut self, _type_id: TypeId) -> Self::Output {
188 Self::default_output()
189 }
190
191 fn visit_readonly_type(&mut self, _inner_type: TypeId) -> Self::Output {
193 Self::default_output()
194 }
195
196 fn visit_unique_symbol(&mut self, _symbol_ref: u32) -> Self::Output {
198 Self::default_output()
199 }
200
201 fn visit_infer(&mut self, _param_info: &TypeParamInfo) -> Self::Output {
203 Self::default_output()
204 }
205
206 fn visit_this_type(&mut self) -> Self::Output {
208 Self::default_output()
209 }
210
211 fn visit_string_intrinsic(
213 &mut self,
214 _kind: StringIntrinsicKind,
215 _type_arg: TypeId,
216 ) -> Self::Output {
217 Self::default_output()
218 }
219
220 fn visit_error(&mut self) -> Self::Output {
222 Self::default_output()
223 }
224
225 fn visit_no_infer(&mut self, _inner: TypeId) -> Self::Output {
228 Self::default_output()
229 }
230
231 fn visit_module_namespace(&mut self, _symbol_ref: u32) -> Self::Output {
233 Self::default_output()
234 }
235
236 fn default_output() -> Self::Output;
242
243 fn visit_type(&mut self, types: &dyn TypeDatabase, type_id: TypeId) -> Self::Output {
247 match types.lookup(type_id) {
248 Some(ref type_key) => self.visit_type_key(types, type_key),
249 None => Self::default_output(),
250 }
251 }
252
253 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
255 match type_key {
256 TypeData::Intrinsic(kind) => self.visit_intrinsic(*kind),
257 TypeData::Literal(value) => self.visit_literal(value),
258 TypeData::Object(id) => self.visit_object(id.0),
259 TypeData::ObjectWithIndex(id) => self.visit_object_with_index(id.0),
260 TypeData::Union(id) => self.visit_union(id.0),
261 TypeData::Intersection(id) => self.visit_intersection(id.0),
262 TypeData::Array(element_type) => self.visit_array(*element_type),
263 TypeData::Tuple(id) => self.visit_tuple(id.0),
264 TypeData::Function(id) => self.visit_function(id.0),
265 TypeData::Callable(id) => self.visit_callable(id.0),
266 TypeData::TypeParameter(info) => self.visit_type_parameter(info),
267 TypeData::BoundParameter(index) => self.visit_bound_parameter(*index),
268 TypeData::Lazy(def_id) => self.visit_lazy(def_id.0),
269 TypeData::Recursive(index) => self.visit_recursive(*index),
270 TypeData::Enum(def_id, member_type) => self.visit_enum(def_id.0, *member_type),
271 TypeData::Application(id) => self.visit_application(id.0),
272 TypeData::Conditional(id) => self.visit_conditional(id.0),
273 TypeData::Mapped(id) => self.visit_mapped(id.0),
274 TypeData::IndexAccess(obj, key) => self.visit_index_access(*obj, *key),
275 TypeData::TemplateLiteral(id) => self.visit_template_literal(id.0),
276 TypeData::TypeQuery(sym_ref) => self.visit_type_query(sym_ref.0),
277 TypeData::KeyOf(type_id) => self.visit_keyof(*type_id),
278 TypeData::ReadonlyType(inner) => self.visit_readonly_type(*inner),
279 TypeData::UniqueSymbol(sym_ref) => self.visit_unique_symbol(sym_ref.0),
280 TypeData::Infer(info) => self.visit_infer(info),
281 TypeData::ThisType => self.visit_this_type(),
282 TypeData::StringIntrinsic { kind, type_arg } => {
283 self.visit_string_intrinsic(*kind, *type_arg)
284 }
285 TypeData::ModuleNamespace(sym_ref) => self.visit_module_namespace(sym_ref.0),
286 TypeData::NoInfer(inner) => self.visit_no_infer(*inner),
287 TypeData::Error => self.visit_error(),
288 }
289 }
290}
291
292pub fn for_each_child<F>(db: &dyn TypeDatabase, key: &TypeData, mut f: F)
331where
332 F: FnMut(TypeId),
333{
334 match key {
335 TypeData::Array(inner)
337 | TypeData::ReadonlyType(inner)
338 | TypeData::KeyOf(inner)
339 | TypeData::NoInfer(inner) => {
340 f(*inner);
341 }
342
343 TypeData::Union(list_id) | TypeData::Intersection(list_id) => {
345 for &member in db.type_list(*list_id).iter() {
346 f(member);
347 }
348 }
349
350 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
352 let shape = db.object_shape(*shape_id);
353 for prop in &shape.properties {
354 f(prop.type_id);
355 f(prop.write_type); }
357 if let Some(ref sig) = shape.string_index {
358 f(sig.key_type);
359 f(sig.value_type);
360 }
361 if let Some(ref sig) = shape.number_index {
362 f(sig.key_type);
363 f(sig.value_type);
364 }
365 }
366
367 TypeData::Tuple(tuple_id) => {
369 for elem in db.tuple_list(*tuple_id).iter() {
370 f(elem.type_id);
371 }
372 }
373
374 TypeData::Function(func_id) => {
376 let sig = db.function_shape(*func_id);
377 f(sig.return_type);
378 if let Some(this_type) = sig.this_type {
379 f(this_type);
380 }
381 if let Some(ref type_predicate) = sig.type_predicate
382 && let Some(type_id) = type_predicate.type_id
383 {
384 f(type_id);
385 }
386 for param in &sig.params {
387 f(param.type_id);
388 }
389 for type_param in &sig.type_params {
390 if let Some(constraint) = type_param.constraint {
391 f(constraint);
392 }
393 if let Some(default) = type_param.default {
394 f(default);
395 }
396 }
397 }
398
399 TypeData::Callable(callable_id) => {
401 let callable = db.callable_shape(*callable_id);
402 for sig in &callable.call_signatures {
403 f(sig.return_type);
404 if let Some(this_type) = sig.this_type {
405 f(this_type);
406 }
407 if let Some(ref type_predicate) = sig.type_predicate
408 && let Some(type_id) = type_predicate.type_id
409 {
410 f(type_id);
411 }
412 for param in &sig.params {
413 f(param.type_id);
414 }
415 for type_param in &sig.type_params {
416 if let Some(constraint) = type_param.constraint {
417 f(constraint);
418 }
419 if let Some(default) = type_param.default {
420 f(default);
421 }
422 }
423 }
424 for sig in &callable.construct_signatures {
425 f(sig.return_type);
426 if let Some(this_type) = sig.this_type {
427 f(this_type);
428 }
429 if let Some(ref type_predicate) = sig.type_predicate
430 && let Some(type_id) = type_predicate.type_id
431 {
432 f(type_id);
433 }
434 for param in &sig.params {
435 f(param.type_id);
436 }
437 for type_param in &sig.type_params {
438 if let Some(constraint) = type_param.constraint {
439 f(constraint);
440 }
441 if let Some(default) = type_param.default {
442 f(default);
443 }
444 }
445 }
446 for prop in &callable.properties {
448 f(prop.type_id);
449 f(prop.write_type);
450 }
451 if let Some(ref sig) = callable.string_index {
452 f(sig.key_type);
453 f(sig.value_type);
454 }
455 if let Some(ref sig) = callable.number_index {
456 f(sig.key_type);
457 f(sig.value_type);
458 }
459 }
460
461 TypeData::Application(app_id) => {
463 let app = db.type_application(*app_id);
464 f(app.base);
465 for &arg in &app.args {
466 f(arg);
467 }
468 }
469
470 TypeData::Conditional(cond_id) => {
472 let cond = db.conditional_type(*cond_id);
473 f(cond.check_type);
474 f(cond.extends_type);
475 f(cond.true_type);
476 f(cond.false_type);
477 }
478
479 TypeData::Mapped(mapped_id) => {
481 let mapped = db.mapped_type(*mapped_id);
482 if let Some(constraint) = mapped.type_param.constraint {
483 f(constraint);
484 }
485 if let Some(default) = mapped.type_param.default {
486 f(default);
487 }
488 f(mapped.constraint);
489 f(mapped.template);
490 if let Some(name_type) = mapped.name_type {
491 f(name_type);
492 }
493 }
494
495 TypeData::IndexAccess(obj, idx) => {
497 f(*obj);
498 f(*idx);
499 }
500
501 TypeData::TemplateLiteral(template_id) => {
503 for span in db.template_list(*template_id).iter() {
504 match span {
505 crate::types::TemplateSpan::Text(_) => {}
506 crate::types::TemplateSpan::Type(type_id) => {
507 f(*type_id);
508 }
509 }
510 }
511 }
512
513 TypeData::StringIntrinsic { type_arg, .. } => {
515 f(*type_arg);
516 }
517
518 TypeData::TypeParameter(info) | TypeData::Infer(info) => {
520 if let Some(constraint) = info.constraint {
521 f(constraint);
522 }
523 }
524
525 TypeData::Enum(_def_id, member_type) => {
527 f(*member_type);
528 }
529
530 TypeData::Intrinsic(_)
532 | TypeData::Literal(_)
533 | TypeData::Lazy(_)
534 | TypeData::Recursive(_)
535 | TypeData::BoundParameter(_)
536 | TypeData::TypeQuery(_)
537 | TypeData::UniqueSymbol(_)
538 | TypeData::ThisType
539 | TypeData::ModuleNamespace(_)
540 | TypeData::Error => {}
541 }
542}
543
544pub fn for_each_child_type_id<F>(db: &dyn TypeDatabase, type_id: TypeId, f: F)
549where
550 F: FnMut(TypeId),
551{
552 let Some(key) = db.lookup(type_id) else {
553 return;
554 };
555 for_each_child(db, &key, f);
556}
557
558pub fn for_each_child_by_id<F>(db: &dyn TypeDatabase, type_id: TypeId, f: F)
565where
566 F: FnMut(TypeId),
567{
568 if let Some(type_data) = db.lookup(type_id) {
569 for_each_child(db, &type_data, f);
570 }
571}
572
573pub fn walk_referenced_types<F>(types: &dyn TypeDatabase, root: TypeId, mut f: F)
575where
576 F: FnMut(TypeId),
577{
578 let mut visited = FxHashSet::default();
579 let mut stack = vec![root];
580
581 while let Some(current) = stack.pop() {
582 if !visited.insert(current) {
583 continue;
584 }
585 f(current);
586
587 let Some(key) = types.lookup(current) else {
588 continue;
589 };
590 for_each_child(types, &key, |child| stack.push(child));
591 }
592}
593
594pub fn collect_lazy_def_ids(types: &dyn TypeDatabase, root: TypeId) -> Vec<DefId> {
596 let mut out = Vec::new();
597 let mut seen = FxHashSet::default();
598
599 walk_referenced_types(types, root, |type_id| {
600 if let Some(TypeData::Lazy(def_id)) = types.lookup(type_id)
601 && seen.insert(def_id)
602 {
603 out.push(def_id);
604 }
605 });
606
607 out
608}
609
610pub fn collect_enum_def_ids(types: &dyn TypeDatabase, root: TypeId) -> Vec<DefId> {
612 let mut out = Vec::new();
613 let mut seen = FxHashSet::default();
614
615 walk_referenced_types(types, root, |type_id| {
616 if let Some(TypeData::Enum(def_id, _)) = types.lookup(type_id)
617 && seen.insert(def_id)
618 {
619 out.push(def_id);
620 }
621 });
622
623 out
624}
625
626pub fn collect_type_queries(types: &dyn TypeDatabase, root: TypeId) -> Vec<SymbolRef> {
628 let mut out = Vec::new();
629 let mut seen = FxHashSet::default();
630
631 walk_referenced_types(types, root, |type_id| {
632 if let Some(TypeData::TypeQuery(symbol_ref)) = types.lookup(type_id)
633 && seen.insert(symbol_ref)
634 {
635 out.push(symbol_ref);
636 }
637 });
638
639 out
640}
641
642#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
648pub enum TypeKind {
649 Primitive,
651 Literal,
653 Object,
655 Array,
657 Tuple,
659 Union,
661 Intersection,
663 Function,
665 Generic,
667 TypeParameter,
669 Conditional,
671 Mapped,
673 IndexAccess,
675 TemplateLiteral,
677 TypeQuery,
679 KeyOf,
681 Reference,
683 Error,
685 Other,
687}
688
689pub struct TypeKindVisitor {
691 pub target_kind: TypeKind,
693}
694
695impl TypeKindVisitor {
696 pub const fn new(target_kind: TypeKind) -> Self {
698 Self { target_kind }
699 }
700
701 pub const fn get_kind(type_key: &TypeData) -> TypeKind {
703 match type_key {
704 TypeData::Intrinsic(_)
705 | TypeData::Enum(_, _)
706 | TypeData::UniqueSymbol(_)
707 | TypeData::StringIntrinsic { .. } => TypeKind::Primitive,
708 TypeData::Literal(_) => TypeKind::Literal,
709 TypeData::Object(_) | TypeData::ObjectWithIndex(_) | TypeData::ModuleNamespace(_) => {
710 TypeKind::Object
711 }
712 TypeData::Array(_) => TypeKind::Array,
713 TypeData::Tuple(_) => TypeKind::Tuple,
714 TypeData::Union(_) => TypeKind::Union,
715 TypeData::Intersection(_) => TypeKind::Intersection,
716 TypeData::Function(_) | TypeData::Callable(_) => TypeKind::Function,
717 TypeData::Application(_) => TypeKind::Generic,
718 TypeData::TypeParameter(_) | TypeData::Infer(_) | TypeData::BoundParameter(_) => {
719 TypeKind::TypeParameter
720 }
721 TypeData::Conditional(_) => TypeKind::Conditional,
722 TypeData::Lazy(_) | TypeData::Recursive(_) => TypeKind::Reference,
723 TypeData::Mapped(_) => TypeKind::Mapped,
724 TypeData::IndexAccess(_, _) => TypeKind::IndexAccess,
725 TypeData::TemplateLiteral(_) => TypeKind::TemplateLiteral,
726 TypeData::TypeQuery(_) => TypeKind::TypeQuery,
727 TypeData::KeyOf(_) => TypeKind::KeyOf,
728 TypeData::ReadonlyType(_inner) => {
729 TypeKind::Other
733 }
734 TypeData::NoInfer(_inner) => {
735 TypeKind::Other
737 }
738 TypeData::ThisType => TypeKind::TypeParameter, TypeData::Error => TypeKind::Error,
740 }
741 }
742
743 pub fn get_kind_of(types: &dyn TypeDatabase, type_id: TypeId) -> TypeKind {
745 match types.lookup(type_id) {
746 Some(ref type_key) => Self::get_kind(type_key),
747 None => TypeKind::Other,
748 }
749 }
750}
751
752impl TypeVisitor for TypeKindVisitor {
753 type Output = bool;
754
755 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
756 self.target_kind == TypeKind::Primitive
757 }
758
759 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
760 self.target_kind == TypeKind::Literal
761 }
762
763 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
764 Self::get_kind(type_key) == self.target_kind
765 }
766
767 fn default_output() -> Self::Output {
768 false
769 }
770}
771
772pub struct TypeCollectorVisitor {
776 pub types: FxHashSet<TypeId>,
778 pub max_depth: usize,
780}
781
782impl TypeCollectorVisitor {
783 pub fn new() -> Self {
785 Self {
786 types: FxHashSet::default(),
787 max_depth: 10,
788 }
789 }
790
791 pub fn with_max_depth(max_depth: usize) -> Self {
793 Self {
794 types: FxHashSet::default(),
795 max_depth,
796 }
797 }
798}
799
800impl Default for TypeCollectorVisitor {
801 fn default() -> Self {
802 Self::new()
803 }
804}
805
806impl TypeVisitor for TypeCollectorVisitor {
807 type Output = ();
808
809 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
810 }
812
813 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
814 }
816
817 fn visit_array(&mut self, element_type: TypeId) -> Self::Output {
818 if self.max_depth > 0 {
819 self.types.insert(element_type);
820 }
821 }
822
823 fn visit_index_access(&mut self, object_type: TypeId, key_type: TypeId) -> Self::Output {
824 if self.max_depth > 0 {
825 self.types.insert(object_type);
826 self.types.insert(key_type);
827 }
828 }
829
830 fn visit_keyof(&mut self, type_id: TypeId) -> Self::Output {
831 if self.max_depth > 0 {
832 self.types.insert(type_id);
833 }
834 }
835
836 fn visit_readonly_type(&mut self, inner_type: TypeId) -> Self::Output {
837 if self.max_depth > 0 {
838 self.types.insert(inner_type);
839 }
840 }
841
842 fn visit_string_intrinsic(
843 &mut self,
844 _kind: StringIntrinsicKind,
845 type_arg: TypeId,
846 ) -> Self::Output {
847 if self.max_depth > 0 {
848 self.types.insert(type_arg);
849 }
850 }
851
852 fn visit_enum(&mut self, _def_id: u32, member_type: TypeId) -> Self::Output {
853 if self.max_depth > 0 {
854 self.types.insert(member_type);
855 }
856 }
857
858 fn default_output() -> Self::Output {}
859}
860
861pub struct TypePredicateVisitor<F>
863where
864 F: Fn(&TypeData) -> bool,
865{
866 pub predicate: F,
868}
869
870impl<F> TypePredicateVisitor<F>
871where
872 F: Fn(&TypeData) -> bool,
873{
874 pub const fn new(predicate: F) -> Self {
876 Self { predicate }
877 }
878}
879
880impl<F> TypeVisitor for TypePredicateVisitor<F>
881where
882 F: Fn(&TypeData) -> bool,
883{
884 type Output = bool;
885
886 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
887 (self.predicate)(type_key)
888 }
889
890 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
891 false
892 }
893
894 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
895 false
896 }
897
898 fn default_output() -> Self::Output {
899 false
900 }
901}
902
903pub fn is_type_kind(types: &dyn TypeDatabase, type_id: TypeId, kind: TypeKind) -> bool {
917 let mut visitor = TypeKindVisitor::new(kind);
918 visitor.visit_type(types, type_id)
919}
920
921pub fn collect_referenced_types(types: &dyn TypeDatabase, type_id: TypeId) -> FxHashSet<TypeId> {
931 collect_all_types(types, type_id)
932}
933
934pub fn test_type<F>(types: &dyn TypeDatabase, type_id: TypeId, predicate: F) -> bool
946where
947 F: Fn(&TypeData) -> bool,
948{
949 let mut visitor = TypePredicateVisitor::new(predicate);
950 visitor.visit_type(types, type_id)
951}
952
953pub struct RecursiveTypeCollector<'a> {
960 types: &'a dyn TypeDatabase,
961 collected: FxHashSet<TypeId>,
962 guard: crate::recursion::RecursionGuard<TypeId>,
963}
964
965impl<'a> RecursiveTypeCollector<'a> {
966 pub fn new(types: &'a dyn TypeDatabase) -> Self {
967 Self {
968 types,
969 collected: FxHashSet::default(),
970 guard: crate::recursion::RecursionGuard::with_profile(
971 crate::recursion::RecursionProfile::ShallowTraversal,
972 ),
973 }
974 }
975
976 pub fn with_max_depth(types: &'a dyn TypeDatabase, max_depth: usize) -> Self {
977 Self {
978 types,
979 collected: FxHashSet::default(),
980 guard: crate::recursion::RecursionGuard::new(max_depth as u32, 100_000),
981 }
982 }
983
984 pub fn collect(&mut self, type_id: TypeId) -> FxHashSet<TypeId> {
986 self.visit(type_id);
987 std::mem::take(&mut self.collected)
988 }
989
990 fn visit(&mut self, type_id: TypeId) {
991 if self.collected.contains(&type_id) {
993 return;
994 }
995
996 match self.guard.enter(type_id) {
998 crate::recursion::RecursionResult::Entered => {}
999 _ => return,
1000 }
1001
1002 self.collected.insert(type_id);
1003
1004 if let Some(key) = self.types.lookup(type_id) {
1005 self.visit_key(&key);
1006 }
1007
1008 self.guard.leave(type_id);
1009 }
1010
1011 fn visit_key(&mut self, key: &TypeData) {
1012 match key {
1013 TypeData::Intrinsic(_)
1014 | TypeData::Literal(_)
1015 | TypeData::Error
1016 | TypeData::ThisType
1017 | TypeData::BoundParameter(_)
1018 | TypeData::Lazy(_)
1019 | TypeData::Recursive(_)
1020 | TypeData::TypeQuery(_)
1021 | TypeData::UniqueSymbol(_)
1022 | TypeData::ModuleNamespace(_) => {
1023 }
1025 TypeData::NoInfer(inner) => {
1026 self.visit(*inner);
1028 }
1029 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
1030 let shape = self.types.object_shape(*shape_id);
1031 for prop in &shape.properties {
1032 self.visit(prop.type_id);
1033 self.visit(prop.write_type);
1034 }
1035 if let Some(ref idx) = shape.string_index {
1036 self.visit(idx.key_type);
1037 self.visit(idx.value_type);
1038 }
1039 if let Some(ref idx) = shape.number_index {
1040 self.visit(idx.key_type);
1041 self.visit(idx.value_type);
1042 }
1043 }
1044 TypeData::Union(list_id) | TypeData::Intersection(list_id) => {
1045 let members = self.types.type_list(*list_id);
1046 for &member in members.iter() {
1047 self.visit(member);
1048 }
1049 }
1050 TypeData::Array(elem) => {
1051 self.visit(*elem);
1052 }
1053 TypeData::Tuple(list_id) => {
1054 let elements = self.types.tuple_list(*list_id);
1055 for elem in elements.iter() {
1056 self.visit(elem.type_id);
1057 }
1058 }
1059 TypeData::Function(shape_id) => {
1060 let shape = self.types.function_shape(*shape_id);
1061 for param in &shape.params {
1062 self.visit(param.type_id);
1063 }
1064 self.visit(shape.return_type);
1065 if let Some(this_type) = shape.this_type {
1066 self.visit(this_type);
1067 }
1068 if let Some(ref type_predicate) = shape.type_predicate
1069 && let Some(type_id) = type_predicate.type_id
1070 {
1071 self.visit(type_id);
1072 }
1073 for type_param in &shape.type_params {
1074 if let Some(constraint) = type_param.constraint {
1075 self.visit(constraint);
1076 }
1077 if let Some(default) = type_param.default {
1078 self.visit(default);
1079 }
1080 }
1081 }
1082 TypeData::Callable(shape_id) => {
1083 let shape = self.types.callable_shape(*shape_id);
1084 for sig in &shape.call_signatures {
1085 for param in &sig.params {
1086 self.visit(param.type_id);
1087 }
1088 self.visit(sig.return_type);
1089 if let Some(this_type) = sig.this_type {
1090 self.visit(this_type);
1091 }
1092 if let Some(ref type_predicate) = sig.type_predicate
1093 && let Some(type_id) = type_predicate.type_id
1094 {
1095 self.visit(type_id);
1096 }
1097 for type_param in &sig.type_params {
1098 if let Some(constraint) = type_param.constraint {
1099 self.visit(constraint);
1100 }
1101 if let Some(default) = type_param.default {
1102 self.visit(default);
1103 }
1104 }
1105 }
1106 for sig in &shape.construct_signatures {
1107 for param in &sig.params {
1108 self.visit(param.type_id);
1109 }
1110 self.visit(sig.return_type);
1111 if let Some(this_type) = sig.this_type {
1112 self.visit(this_type);
1113 }
1114 if let Some(ref type_predicate) = sig.type_predicate
1115 && let Some(type_id) = type_predicate.type_id
1116 {
1117 self.visit(type_id);
1118 }
1119 for type_param in &sig.type_params {
1120 if let Some(constraint) = type_param.constraint {
1121 self.visit(constraint);
1122 }
1123 if let Some(default) = type_param.default {
1124 self.visit(default);
1125 }
1126 }
1127 }
1128 for prop in &shape.properties {
1129 self.visit(prop.type_id);
1130 self.visit(prop.write_type);
1131 }
1132 if let Some(ref sig) = shape.string_index {
1133 self.visit(sig.key_type);
1134 self.visit(sig.value_type);
1135 }
1136 if let Some(ref sig) = shape.number_index {
1137 self.visit(sig.key_type);
1138 self.visit(sig.value_type);
1139 }
1140 }
1141 TypeData::TypeParameter(info) | TypeData::Infer(info) => {
1142 if let Some(constraint) = info.constraint {
1143 self.visit(constraint);
1144 }
1145 if let Some(default) = info.default {
1146 self.visit(default);
1147 }
1148 }
1149 TypeData::Application(app_id) => {
1150 let app = self.types.type_application(*app_id);
1151 self.visit(app.base);
1152 for &arg in &app.args {
1153 self.visit(arg);
1154 }
1155 }
1156 TypeData::Conditional(cond_id) => {
1157 let cond = self.types.conditional_type(*cond_id);
1158 self.visit(cond.check_type);
1159 self.visit(cond.extends_type);
1160 self.visit(cond.true_type);
1161 self.visit(cond.false_type);
1162 }
1163 TypeData::Mapped(mapped_id) => {
1164 let mapped = self.types.mapped_type(*mapped_id);
1165 if let Some(constraint) = mapped.type_param.constraint {
1166 self.visit(constraint);
1167 }
1168 if let Some(default) = mapped.type_param.default {
1169 self.visit(default);
1170 }
1171 self.visit(mapped.constraint);
1172 self.visit(mapped.template);
1173 if let Some(name_type) = mapped.name_type {
1174 self.visit(name_type);
1175 }
1176 }
1177 TypeData::IndexAccess(obj, idx) => {
1178 self.visit(*obj);
1179 self.visit(*idx);
1180 }
1181 TypeData::TemplateLiteral(list_id) => {
1182 let spans = self.types.template_list(*list_id);
1183 for span in spans.iter() {
1184 if let crate::types::TemplateSpan::Type(type_id) = span {
1185 self.visit(*type_id);
1186 }
1187 }
1188 }
1189 TypeData::KeyOf(inner) | TypeData::ReadonlyType(inner) => {
1190 self.visit(*inner);
1191 }
1192 TypeData::StringIntrinsic { type_arg, .. } => {
1193 self.visit(*type_arg);
1194 }
1195 TypeData::Enum(_def_id, member_type) => {
1196 self.visit(*member_type);
1198 }
1199 }
1200 }
1201}
1202
1203pub fn collect_all_types(types: &dyn TypeDatabase, type_id: TypeId) -> FxHashSet<TypeId> {
1205 let mut collector = RecursiveTypeCollector::new(types);
1206 collector.collect(type_id)
1207}
1208
1209pub struct ConstAssertionVisitor<'a> {
1222 pub db: &'a dyn TypeDatabase,
1224 pub guard: crate::recursion::RecursionGuard<TypeId>,
1226}
1227
1228impl<'a> ConstAssertionVisitor<'a> {
1229 pub fn new(db: &'a dyn TypeDatabase) -> Self {
1231 Self {
1232 db,
1233 guard: crate::recursion::RecursionGuard::with_profile(
1234 crate::recursion::RecursionProfile::ConstAssertion,
1235 ),
1236 }
1237 }
1238
1239 pub fn apply_const_assertion(&mut self, type_id: TypeId) -> TypeId {
1241 match self.guard.enter(type_id) {
1243 crate::recursion::RecursionResult::Entered => {}
1244 _ => return type_id,
1245 }
1246
1247 let result = match self.db.lookup(type_id) {
1248 Some(TypeData::Array(element_type)) => {
1250 let const_element = self.apply_const_assertion(element_type);
1251 let tuple_elem = TupleElement {
1253 type_id: const_element,
1254 name: None,
1255 optional: false,
1256 rest: false,
1257 };
1258 let tuple_type = self.db.tuple(vec![tuple_elem]);
1259 self.db.readonly_type(tuple_type)
1260 }
1261
1262 Some(TypeData::Tuple(list_id)) => {
1264 let elements = self.db.tuple_list(list_id);
1265 let const_elements: Vec<TupleElement> = elements
1266 .iter()
1267 .map(|elem| {
1268 let const_type = self.apply_const_assertion(elem.type_id);
1269 TupleElement {
1270 type_id: const_type,
1271 name: elem.name,
1272 optional: elem.optional,
1273 rest: elem.rest,
1274 }
1275 })
1276 .collect();
1277 let tuple_type = self.db.tuple(const_elements);
1278 self.db.readonly_type(tuple_type)
1279 }
1280
1281 Some(TypeData::Object(shape_id)) => {
1283 let shape = self.db.object_shape(shape_id);
1284 let mut new_props = Vec::with_capacity(shape.properties.len());
1285
1286 for prop in &shape.properties {
1287 let const_prop_type = self.apply_const_assertion(prop.type_id);
1288 let const_write_type = self.apply_const_assertion(prop.write_type);
1289 new_props.push(crate::types::PropertyInfo {
1290 name: prop.name,
1291 type_id: const_prop_type,
1292 write_type: const_write_type,
1293 optional: prop.optional,
1294 readonly: true, is_method: prop.is_method,
1296 visibility: prop.visibility,
1297 parent_id: prop.parent_id,
1298 });
1299 }
1300
1301 self.db.object(new_props)
1302 }
1303
1304 Some(TypeData::ObjectWithIndex(shape_id)) => {
1306 let shape = self.db.object_shape(shape_id);
1307 let mut new_props = Vec::with_capacity(shape.properties.len());
1308
1309 for prop in &shape.properties {
1310 let const_prop_type = self.apply_const_assertion(prop.type_id);
1311 let const_write_type = self.apply_const_assertion(prop.write_type);
1312 new_props.push(crate::types::PropertyInfo {
1313 name: prop.name,
1314 type_id: const_prop_type,
1315 write_type: const_write_type,
1316 optional: prop.optional,
1317 readonly: true, is_method: prop.is_method,
1319 visibility: prop.visibility,
1320 parent_id: prop.parent_id,
1321 });
1322 }
1323
1324 let string_index =
1326 shape
1327 .string_index
1328 .as_ref()
1329 .map(|idx| crate::types::IndexSignature {
1330 key_type: idx.key_type,
1331 value_type: self.apply_const_assertion(idx.value_type),
1332 readonly: true,
1333 });
1334
1335 let number_index =
1336 shape
1337 .number_index
1338 .as_ref()
1339 .map(|idx| crate::types::IndexSignature {
1340 key_type: idx.key_type,
1341 value_type: self.apply_const_assertion(idx.value_type),
1342 readonly: true,
1343 });
1344
1345 let mut new_shape = (*shape).clone();
1346 new_shape.properties = new_props;
1347 new_shape.string_index = string_index;
1348 new_shape.number_index = number_index;
1349
1350 self.db.object_with_index(new_shape)
1351 }
1352
1353 Some(TypeData::ReadonlyType(inner)) => {
1355 let const_inner = self.apply_const_assertion(inner);
1356 self.db.readonly_type(const_inner)
1357 }
1358
1359 Some(TypeData::Union(list_id)) => {
1361 let members = self.db.type_list(list_id);
1362 let const_members: Vec<TypeId> = members
1363 .iter()
1364 .map(|&m| self.apply_const_assertion(m))
1365 .collect();
1366 self.db.union(const_members)
1367 }
1368
1369 Some(TypeData::Intersection(list_id)) => {
1371 let members = self.db.type_list(list_id);
1372 let const_members: Vec<TypeId> = members
1373 .iter()
1374 .map(|&m| self.apply_const_assertion(m))
1375 .collect();
1376 self.db.intersection(const_members)
1377 }
1378
1379 _ => type_id,
1381 };
1382
1383 self.guard.leave(type_id);
1384 result
1385 }
1386}