1use crate::def::DefId;
42use crate::types::{
43 IntrinsicKind, ObjectShapeId, StringIntrinsicKind, TupleElement, TypeParamInfo,
44};
45use crate::{LiteralValue, SymbolRef, TypeData, TypeDatabase, TypeId};
46use rustc_hash::{FxHashMap, FxHashSet};
47
48pub use crate::visitor_extract::*;
50
51pub trait TypeVisitor: Sized {
61 type Output;
63
64 fn visit_intrinsic(&mut self, kind: IntrinsicKind) -> Self::Output;
70
71 fn visit_literal(&mut self, value: &LiteralValue) -> Self::Output;
73
74 fn visit_object(&mut self, _shape_id: u32) -> Self::Output {
80 Self::default_output()
81 }
82
83 fn visit_object_with_index(&mut self, _shape_id: u32) -> Self::Output {
85 Self::default_output()
86 }
87
88 fn visit_union(&mut self, _list_id: u32) -> Self::Output {
90 Self::default_output()
91 }
92
93 fn visit_intersection(&mut self, _list_id: u32) -> Self::Output {
95 Self::default_output()
96 }
97
98 fn visit_array(&mut self, _element_type: TypeId) -> Self::Output {
100 Self::default_output()
101 }
102
103 fn visit_tuple(&mut self, _list_id: u32) -> Self::Output {
105 Self::default_output()
106 }
107
108 fn visit_function(&mut self, _shape_id: u32) -> Self::Output {
110 Self::default_output()
111 }
112
113 fn visit_callable(&mut self, _shape_id: u32) -> Self::Output {
115 Self::default_output()
116 }
117
118 fn visit_type_parameter(&mut self, _param_info: &TypeParamInfo) -> Self::Output {
120 Self::default_output()
121 }
122
123 fn visit_bound_parameter(&mut self, _de_bruijn_index: u32) -> Self::Output {
129 Self::default_output()
130 }
131
132 fn visit_ref(&mut self, _symbol_ref: u32) -> Self::Output {
134 Self::default_output()
135 }
136
137 fn visit_enum(&mut self, _def_id: u32, _member_type: TypeId) -> Self::Output {
139 Self::default_output()
140 }
141
142 fn visit_lazy(&mut self, _def_id: u32) -> Self::Output {
144 Self::default_output()
145 }
146
147 fn visit_recursive(&mut self, _de_bruijn_index: u32) -> Self::Output {
152 Self::default_output()
153 }
154
155 fn visit_application(&mut self, _app_id: u32) -> Self::Output {
157 Self::default_output()
158 }
159
160 fn visit_conditional(&mut self, _cond_id: u32) -> Self::Output {
162 Self::default_output()
163 }
164
165 fn visit_mapped(&mut self, _mapped_id: u32) -> Self::Output {
167 Self::default_output()
168 }
169
170 fn visit_index_access(&mut self, _object_type: TypeId, _key_type: TypeId) -> Self::Output {
172 Self::default_output()
173 }
174
175 fn visit_template_literal(&mut self, _template_id: u32) -> Self::Output {
177 Self::default_output()
178 }
179
180 fn visit_type_query(&mut self, _symbol_ref: u32) -> Self::Output {
182 Self::default_output()
183 }
184
185 fn visit_keyof(&mut self, _type_id: TypeId) -> Self::Output {
187 Self::default_output()
188 }
189
190 fn visit_readonly_type(&mut self, _inner_type: TypeId) -> Self::Output {
192 Self::default_output()
193 }
194
195 fn visit_unique_symbol(&mut self, _symbol_ref: u32) -> Self::Output {
197 Self::default_output()
198 }
199
200 fn visit_infer(&mut self, _param_info: &TypeParamInfo) -> Self::Output {
202 Self::default_output()
203 }
204
205 fn visit_this_type(&mut self) -> Self::Output {
207 Self::default_output()
208 }
209
210 fn visit_string_intrinsic(
212 &mut self,
213 _kind: StringIntrinsicKind,
214 _type_arg: TypeId,
215 ) -> Self::Output {
216 Self::default_output()
217 }
218
219 fn visit_error(&mut self) -> Self::Output {
221 Self::default_output()
222 }
223
224 fn visit_no_infer(&mut self, _inner: TypeId) -> Self::Output {
227 Self::default_output()
228 }
229
230 fn visit_module_namespace(&mut self, _symbol_ref: u32) -> Self::Output {
232 Self::default_output()
233 }
234
235 fn default_output() -> Self::Output;
241
242 fn visit_type(&mut self, types: &dyn TypeDatabase, type_id: TypeId) -> Self::Output {
246 match types.lookup(type_id) {
247 Some(ref type_key) => self.visit_type_key(types, type_key),
248 None => Self::default_output(),
249 }
250 }
251
252 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
254 match type_key {
255 TypeData::Intrinsic(kind) => self.visit_intrinsic(*kind),
256 TypeData::Literal(value) => self.visit_literal(value),
257 TypeData::Object(id) => self.visit_object(id.0),
258 TypeData::ObjectWithIndex(id) => self.visit_object_with_index(id.0),
259 TypeData::Union(id) => self.visit_union(id.0),
260 TypeData::Intersection(id) => self.visit_intersection(id.0),
261 TypeData::Array(element_type) => self.visit_array(*element_type),
262 TypeData::Tuple(id) => self.visit_tuple(id.0),
263 TypeData::Function(id) => self.visit_function(id.0),
264 TypeData::Callable(id) => self.visit_callable(id.0),
265 TypeData::TypeParameter(info) => self.visit_type_parameter(info),
266 TypeData::BoundParameter(index) => self.visit_bound_parameter(*index),
267 TypeData::Lazy(def_id) => self.visit_lazy(def_id.0),
268 TypeData::Recursive(index) => self.visit_recursive(*index),
269 TypeData::Enum(def_id, member_type) => self.visit_enum(def_id.0, *member_type),
270 TypeData::Application(id) => self.visit_application(id.0),
271 TypeData::Conditional(id) => self.visit_conditional(id.0),
272 TypeData::Mapped(id) => self.visit_mapped(id.0),
273 TypeData::IndexAccess(obj, key) => self.visit_index_access(*obj, *key),
274 TypeData::TemplateLiteral(id) => self.visit_template_literal(id.0),
275 TypeData::TypeQuery(sym_ref) => self.visit_type_query(sym_ref.0),
276 TypeData::KeyOf(type_id) => self.visit_keyof(*type_id),
277 TypeData::ReadonlyType(inner) => self.visit_readonly_type(*inner),
278 TypeData::UniqueSymbol(sym_ref) => self.visit_unique_symbol(sym_ref.0),
279 TypeData::Infer(info) => self.visit_infer(info),
280 TypeData::ThisType => self.visit_this_type(),
281 TypeData::StringIntrinsic { kind, type_arg } => {
282 self.visit_string_intrinsic(*kind, *type_arg)
283 }
284 TypeData::ModuleNamespace(sym_ref) => self.visit_module_namespace(sym_ref.0),
285 TypeData::NoInfer(inner) => self.visit_no_infer(*inner),
286 TypeData::Error => self.visit_error(),
287 }
288 }
289}
290
291pub fn for_each_child<F>(db: &dyn TypeDatabase, key: &TypeData, mut f: F)
330where
331 F: FnMut(TypeId),
332{
333 match key {
334 TypeData::Array(inner)
336 | TypeData::ReadonlyType(inner)
337 | TypeData::KeyOf(inner)
338 | TypeData::NoInfer(inner) => {
339 f(*inner);
340 }
341
342 TypeData::Union(list_id) | TypeData::Intersection(list_id) => {
344 for &member in db.type_list(*list_id).iter() {
345 f(member);
346 }
347 }
348
349 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
351 let shape = db.object_shape(*shape_id);
352 for prop in &shape.properties {
353 f(prop.type_id);
354 f(prop.write_type); }
356 if let Some(ref sig) = shape.string_index {
357 f(sig.key_type);
358 f(sig.value_type);
359 }
360 if let Some(ref sig) = shape.number_index {
361 f(sig.key_type);
362 f(sig.value_type);
363 }
364 }
365
366 TypeData::Tuple(tuple_id) => {
368 for elem in db.tuple_list(*tuple_id).iter() {
369 f(elem.type_id);
370 }
371 }
372
373 TypeData::Function(func_id) => {
375 let sig = db.function_shape(*func_id);
376 f(sig.return_type);
377 if let Some(this_type) = sig.this_type {
378 f(this_type);
379 }
380 if let Some(ref type_predicate) = sig.type_predicate
381 && let Some(type_id) = type_predicate.type_id
382 {
383 f(type_id);
384 }
385 for param in &sig.params {
386 f(param.type_id);
387 }
388 for type_param in &sig.type_params {
389 if let Some(constraint) = type_param.constraint {
390 f(constraint);
391 }
392 if let Some(default) = type_param.default {
393 f(default);
394 }
395 }
396 }
397
398 TypeData::Callable(callable_id) => {
400 let callable = db.callable_shape(*callable_id);
401 for sig in &callable.call_signatures {
402 f(sig.return_type);
403 if let Some(this_type) = sig.this_type {
404 f(this_type);
405 }
406 if let Some(ref type_predicate) = sig.type_predicate
407 && let Some(type_id) = type_predicate.type_id
408 {
409 f(type_id);
410 }
411 for param in &sig.params {
412 f(param.type_id);
413 }
414 for type_param in &sig.type_params {
415 if let Some(constraint) = type_param.constraint {
416 f(constraint);
417 }
418 if let Some(default) = type_param.default {
419 f(default);
420 }
421 }
422 }
423 for sig in &callable.construct_signatures {
424 f(sig.return_type);
425 if let Some(this_type) = sig.this_type {
426 f(this_type);
427 }
428 if let Some(ref type_predicate) = sig.type_predicate
429 && let Some(type_id) = type_predicate.type_id
430 {
431 f(type_id);
432 }
433 for param in &sig.params {
434 f(param.type_id);
435 }
436 for type_param in &sig.type_params {
437 if let Some(constraint) = type_param.constraint {
438 f(constraint);
439 }
440 if let Some(default) = type_param.default {
441 f(default);
442 }
443 }
444 }
445 for prop in &callable.properties {
447 f(prop.type_id);
448 f(prop.write_type);
449 }
450 if let Some(ref sig) = callable.string_index {
451 f(sig.key_type);
452 f(sig.value_type);
453 }
454 if let Some(ref sig) = callable.number_index {
455 f(sig.key_type);
456 f(sig.value_type);
457 }
458 }
459
460 TypeData::Application(app_id) => {
462 let app = db.type_application(*app_id);
463 f(app.base);
464 for &arg in &app.args {
465 f(arg);
466 }
467 }
468
469 TypeData::Conditional(cond_id) => {
471 let cond = db.conditional_type(*cond_id);
472 f(cond.check_type);
473 f(cond.extends_type);
474 f(cond.true_type);
475 f(cond.false_type);
476 }
477
478 TypeData::Mapped(mapped_id) => {
480 let mapped = db.mapped_type(*mapped_id);
481 if let Some(constraint) = mapped.type_param.constraint {
482 f(constraint);
483 }
484 if let Some(default) = mapped.type_param.default {
485 f(default);
486 }
487 f(mapped.constraint);
488 f(mapped.template);
489 if let Some(name_type) = mapped.name_type {
490 f(name_type);
491 }
492 }
493
494 TypeData::IndexAccess(obj, idx) => {
496 f(*obj);
497 f(*idx);
498 }
499
500 TypeData::TemplateLiteral(template_id) => {
502 for span in db.template_list(*template_id).iter() {
503 match span {
504 crate::types::TemplateSpan::Text(_) => {}
505 crate::types::TemplateSpan::Type(type_id) => {
506 f(*type_id);
507 }
508 }
509 }
510 }
511
512 TypeData::StringIntrinsic { type_arg, .. } => {
514 f(*type_arg);
515 }
516
517 TypeData::TypeParameter(info) | TypeData::Infer(info) => {
519 if let Some(constraint) = info.constraint {
520 f(constraint);
521 }
522 }
523
524 TypeData::Enum(_def_id, member_type) => {
526 f(*member_type);
527 }
528
529 TypeData::Intrinsic(_)
531 | TypeData::Literal(_)
532 | TypeData::Lazy(_)
533 | TypeData::Recursive(_)
534 | TypeData::BoundParameter(_)
535 | TypeData::TypeQuery(_)
536 | TypeData::UniqueSymbol(_)
537 | TypeData::ThisType
538 | TypeData::ModuleNamespace(_)
539 | TypeData::Error => {}
540 }
541}
542
543pub fn walk_referenced_types<F>(types: &dyn TypeDatabase, root: TypeId, mut f: F)
547where
548 F: FnMut(TypeId),
549{
550 let mut visited = FxHashSet::default();
551 let mut stack = vec![root];
552
553 while let Some(current) = stack.pop() {
554 if !visited.insert(current) {
555 continue;
556 }
557 f(current);
558
559 let Some(key) = types.lookup(current) else {
560 continue;
561 };
562 for_each_child(types, &key, |child| stack.push(child));
563 }
564}
565
566pub fn collect_lazy_def_ids(types: &dyn TypeDatabase, root: TypeId) -> Vec<DefId> {
568 let mut out = Vec::new();
569 let mut seen = FxHashSet::default();
570
571 walk_referenced_types(types, root, |type_id| {
572 if let Some(TypeData::Lazy(def_id)) = types.lookup(type_id)
573 && seen.insert(def_id)
574 {
575 out.push(def_id);
576 }
577 });
578
579 out
580}
581
582pub fn collect_enum_def_ids(types: &dyn TypeDatabase, root: TypeId) -> Vec<DefId> {
584 let mut out = Vec::new();
585 let mut seen = FxHashSet::default();
586
587 walk_referenced_types(types, root, |type_id| {
588 if let Some(TypeData::Enum(def_id, _)) = types.lookup(type_id)
589 && seen.insert(def_id)
590 {
591 out.push(def_id);
592 }
593 });
594
595 out
596}
597
598pub fn collect_type_queries(types: &dyn TypeDatabase, root: TypeId) -> Vec<SymbolRef> {
600 let mut out = Vec::new();
601 let mut seen = FxHashSet::default();
602
603 walk_referenced_types(types, root, |type_id| {
604 if let Some(TypeData::TypeQuery(symbol_ref)) = types.lookup(type_id)
605 && seen.insert(symbol_ref)
606 {
607 out.push(symbol_ref);
608 }
609 });
610
611 out
612}
613
614#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
620pub enum TypeKind {
621 Primitive,
623 Literal,
625 Object,
627 Array,
629 Tuple,
631 Union,
633 Intersection,
635 Function,
637 Generic,
639 TypeParameter,
641 Conditional,
643 Mapped,
645 IndexAccess,
647 TemplateLiteral,
649 TypeQuery,
651 KeyOf,
653 Reference,
655 Error,
657 Other,
659}
660
661pub struct TypeKindVisitor {
663 pub target_kind: TypeKind,
665}
666
667impl TypeKindVisitor {
668 pub const fn new(target_kind: TypeKind) -> Self {
670 Self { target_kind }
671 }
672
673 pub const fn get_kind(type_key: &TypeData) -> TypeKind {
675 match type_key {
676 TypeData::Intrinsic(_)
677 | TypeData::Enum(_, _)
678 | TypeData::UniqueSymbol(_)
679 | TypeData::StringIntrinsic { .. } => TypeKind::Primitive,
680 TypeData::Literal(_) => TypeKind::Literal,
681 TypeData::Object(_) | TypeData::ObjectWithIndex(_) | TypeData::ModuleNamespace(_) => {
682 TypeKind::Object
683 }
684 TypeData::Array(_) => TypeKind::Array,
685 TypeData::Tuple(_) => TypeKind::Tuple,
686 TypeData::Union(_) => TypeKind::Union,
687 TypeData::Intersection(_) => TypeKind::Intersection,
688 TypeData::Function(_) | TypeData::Callable(_) => TypeKind::Function,
689 TypeData::Application(_) => TypeKind::Generic,
690 TypeData::TypeParameter(_) | TypeData::Infer(_) | TypeData::BoundParameter(_) => {
691 TypeKind::TypeParameter
692 }
693 TypeData::Conditional(_) => TypeKind::Conditional,
694 TypeData::Lazy(_) | TypeData::Recursive(_) => TypeKind::Reference,
695 TypeData::Mapped(_) => TypeKind::Mapped,
696 TypeData::IndexAccess(_, _) => TypeKind::IndexAccess,
697 TypeData::TemplateLiteral(_) => TypeKind::TemplateLiteral,
698 TypeData::TypeQuery(_) => TypeKind::TypeQuery,
699 TypeData::KeyOf(_) => TypeKind::KeyOf,
700 TypeData::ReadonlyType(_inner) => {
701 TypeKind::Other
705 }
706 TypeData::NoInfer(_inner) => {
707 TypeKind::Other
709 }
710 TypeData::ThisType => TypeKind::TypeParameter, TypeData::Error => TypeKind::Error,
712 }
713 }
714
715 pub fn get_kind_of(types: &dyn TypeDatabase, type_id: TypeId) -> TypeKind {
717 match types.lookup(type_id) {
718 Some(ref type_key) => Self::get_kind(type_key),
719 None => TypeKind::Other,
720 }
721 }
722}
723
724impl TypeVisitor for TypeKindVisitor {
725 type Output = bool;
726
727 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
728 self.target_kind == TypeKind::Primitive
729 }
730
731 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
732 self.target_kind == TypeKind::Literal
733 }
734
735 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
736 Self::get_kind(type_key) == self.target_kind
737 }
738
739 fn default_output() -> Self::Output {
740 false
741 }
742}
743
744pub struct TypeCollectorVisitor {
748 pub types: FxHashSet<TypeId>,
750 pub max_depth: usize,
752}
753
754impl TypeCollectorVisitor {
755 pub fn new() -> Self {
757 Self {
758 types: FxHashSet::default(),
759 max_depth: 10,
760 }
761 }
762
763 pub fn with_max_depth(max_depth: usize) -> Self {
765 Self {
766 types: FxHashSet::default(),
767 max_depth,
768 }
769 }
770}
771
772impl Default for TypeCollectorVisitor {
773 fn default() -> Self {
774 Self::new()
775 }
776}
777
778impl TypeVisitor for TypeCollectorVisitor {
779 type Output = ();
780
781 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
782 }
784
785 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
786 }
788
789 fn visit_array(&mut self, element_type: TypeId) -> Self::Output {
790 if self.max_depth > 0 {
791 self.types.insert(element_type);
792 }
793 }
794
795 fn visit_index_access(&mut self, object_type: TypeId, key_type: TypeId) -> Self::Output {
796 if self.max_depth > 0 {
797 self.types.insert(object_type);
798 self.types.insert(key_type);
799 }
800 }
801
802 fn visit_keyof(&mut self, type_id: TypeId) -> Self::Output {
803 if self.max_depth > 0 {
804 self.types.insert(type_id);
805 }
806 }
807
808 fn visit_readonly_type(&mut self, inner_type: TypeId) -> Self::Output {
809 if self.max_depth > 0 {
810 self.types.insert(inner_type);
811 }
812 }
813
814 fn visit_string_intrinsic(
815 &mut self,
816 _kind: StringIntrinsicKind,
817 type_arg: TypeId,
818 ) -> Self::Output {
819 if self.max_depth > 0 {
820 self.types.insert(type_arg);
821 }
822 }
823
824 fn visit_enum(&mut self, _def_id: u32, member_type: TypeId) -> Self::Output {
825 if self.max_depth > 0 {
826 self.types.insert(member_type);
827 }
828 }
829
830 fn default_output() -> Self::Output {}
831}
832
833pub struct TypePredicateVisitor<F>
835where
836 F: Fn(&TypeData) -> bool,
837{
838 pub predicate: F,
840}
841
842impl<F> TypePredicateVisitor<F>
843where
844 F: Fn(&TypeData) -> bool,
845{
846 pub const fn new(predicate: F) -> Self {
848 Self { predicate }
849 }
850}
851
852impl<F> TypeVisitor for TypePredicateVisitor<F>
853where
854 F: Fn(&TypeData) -> bool,
855{
856 type Output = bool;
857
858 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
859 (self.predicate)(type_key)
860 }
861
862 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
863 false
864 }
865
866 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
867 false
868 }
869
870 fn default_output() -> Self::Output {
871 false
872 }
873}
874
875pub fn is_type_kind(types: &dyn TypeDatabase, type_id: TypeId, kind: TypeKind) -> bool {
889 let mut visitor = TypeKindVisitor::new(kind);
890 visitor.visit_type(types, type_id)
891}
892
893pub fn collect_referenced_types(types: &dyn TypeDatabase, type_id: TypeId) -> FxHashSet<TypeId> {
903 collect_all_types(types, type_id)
904}
905
906pub fn test_type<F>(types: &dyn TypeDatabase, type_id: TypeId, predicate: F) -> bool
918where
919 F: Fn(&TypeData) -> bool,
920{
921 let mut visitor = TypePredicateVisitor::new(predicate);
922 visitor.visit_type(types, type_id)
923}
924
925pub fn is_literal_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
933 matches!(types.lookup(type_id), Some(TypeData::Literal(_)))
934}
935
936pub fn is_module_namespace_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
940 matches!(types.lookup(type_id), Some(TypeData::ModuleNamespace(_)))
941}
942
943pub fn is_function_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
947 is_function_type_impl(types, type_id)
948}
949
950fn is_function_type_impl(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
951 match types.lookup(type_id) {
952 Some(TypeData::Function(_) | TypeData::Callable(_)) => true,
953 Some(TypeData::Intersection(members)) => {
954 let members = types.type_list(members);
955 members
956 .iter()
957 .any(|&member| is_function_type_impl(types, member))
958 }
959 _ => false,
960 }
961}
962
963pub fn is_object_like_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
967 is_object_like_type_impl(types, type_id)
968}
969
970fn is_object_like_type_impl(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
971 match types.lookup(type_id) {
972 Some(
973 TypeData::Object(_)
974 | TypeData::ObjectWithIndex(_)
975 | TypeData::Array(_)
976 | TypeData::Tuple(_)
977 | TypeData::Mapped(_)
978 | TypeData::Function(_)
979 | TypeData::Callable(_)
980 | TypeData::Intrinsic(IntrinsicKind::Object | IntrinsicKind::Function),
981 ) => true,
982 Some(TypeData::ReadonlyType(inner)) => is_object_like_type_impl(types, inner),
983 Some(TypeData::Intersection(members)) => {
984 let members = types.type_list(members);
985 members
986 .iter()
987 .all(|&member| is_object_like_type_impl(types, member))
988 }
989 Some(TypeData::TypeParameter(info) | TypeData::Infer(info)) => info
990 .constraint
991 .is_some_and(|constraint| is_object_like_type_impl(types, constraint)),
992 _ => false,
993 }
994}
995
996pub fn is_empty_object_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
998 match types.lookup(type_id) {
999 Some(TypeData::Object(shape_id)) => {
1000 let shape = types.object_shape(shape_id);
1001 shape.properties.is_empty()
1002 }
1003 Some(TypeData::ObjectWithIndex(shape_id)) => {
1004 let shape = types.object_shape(shape_id);
1005 shape.properties.is_empty()
1006 && shape.string_index.is_none()
1007 && shape.number_index.is_none()
1008 }
1009 _ => false,
1010 }
1011}
1012
1013pub fn is_primitive_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1015 if type_id.is_intrinsic() {
1017 return true;
1018 }
1019 matches!(
1020 types.lookup(type_id),
1021 Some(TypeData::Intrinsic(_) | TypeData::Literal(_))
1022 )
1023}
1024
1025pub fn is_union_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1027 matches!(types.lookup(type_id), Some(TypeData::Union(_)))
1028}
1029
1030pub fn is_intersection_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1032 matches!(types.lookup(type_id), Some(TypeData::Intersection(_)))
1033}
1034
1035pub fn is_array_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1037 matches!(types.lookup(type_id), Some(TypeData::Array(_)))
1038}
1039
1040pub fn is_tuple_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1042 matches!(types.lookup(type_id), Some(TypeData::Tuple(_)))
1043}
1044
1045pub fn is_type_parameter(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1047 matches!(
1048 types.lookup(type_id),
1049 Some(TypeData::TypeParameter(_) | TypeData::Infer(_))
1050 )
1051}
1052
1053pub fn is_conditional_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1055 matches!(types.lookup(type_id), Some(TypeData::Conditional(_)))
1056}
1057
1058pub fn is_mapped_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1060 matches!(types.lookup(type_id), Some(TypeData::Mapped(_)))
1061}
1062
1063pub fn is_index_access_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1065 matches!(types.lookup(type_id), Some(TypeData::IndexAccess(_, _)))
1066}
1067
1068pub fn is_template_literal_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1070 matches!(types.lookup(type_id), Some(TypeData::TemplateLiteral(_)))
1071}
1072
1073pub fn is_type_reference(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1075 matches!(
1076 types.lookup(type_id),
1077 Some(TypeData::Lazy(_) | TypeData::Recursive(_))
1078 )
1079}
1080
1081pub fn is_generic_application(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1083 matches!(types.lookup(type_id), Some(TypeData::Application(_)))
1084}
1085
1086pub fn is_unit_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1105 is_unit_type_impl(types, type_id, 0)
1106}
1107
1108const MAX_UNIT_TYPE_DEPTH: u32 = 10;
1109
1110fn is_unit_type_impl(types: &dyn TypeDatabase, type_id: TypeId, depth: u32) -> bool {
1111 if depth > MAX_UNIT_TYPE_DEPTH {
1113 return false;
1114 }
1115
1116 if type_id == TypeId::NULL
1118 || type_id == TypeId::UNDEFINED
1119 || type_id == TypeId::VOID
1120 || type_id == TypeId::NEVER
1121 {
1122 return true;
1123 }
1124
1125 match types.lookup(type_id) {
1126 Some(TypeData::Literal(_))
1128 | Some(TypeData::Enum(_, _))
1129 | Some(TypeData::UniqueSymbol(_)) => true,
1130
1131 Some(TypeData::Tuple(list_id)) => {
1133 let elements = types.tuple_list(list_id);
1134 if elements.iter().any(|e| e.rest) {
1136 return false;
1137 }
1138 elements
1140 .iter()
1141 .all(|e| is_unit_type_impl(types, e.type_id, depth + 1))
1142 }
1143
1144 _ => false,
1148 }
1149}
1150
1151pub struct RecursiveTypeCollector<'a> {
1158 types: &'a dyn TypeDatabase,
1159 collected: FxHashSet<TypeId>,
1160 guard: crate::recursion::RecursionGuard<TypeId>,
1161}
1162
1163impl<'a> RecursiveTypeCollector<'a> {
1164 pub fn new(types: &'a dyn TypeDatabase) -> Self {
1165 Self {
1166 types,
1167 collected: FxHashSet::default(),
1168 guard: crate::recursion::RecursionGuard::with_profile(
1169 crate::recursion::RecursionProfile::ShallowTraversal,
1170 ),
1171 }
1172 }
1173
1174 pub fn with_max_depth(types: &'a dyn TypeDatabase, max_depth: usize) -> Self {
1175 Self {
1176 types,
1177 collected: FxHashSet::default(),
1178 guard: crate::recursion::RecursionGuard::new(max_depth as u32, 100_000),
1179 }
1180 }
1181
1182 pub fn collect(&mut self, type_id: TypeId) -> FxHashSet<TypeId> {
1184 self.visit(type_id);
1185 std::mem::take(&mut self.collected)
1186 }
1187
1188 fn visit(&mut self, type_id: TypeId) {
1189 if self.collected.contains(&type_id) {
1191 return;
1192 }
1193
1194 match self.guard.enter(type_id) {
1196 crate::recursion::RecursionResult::Entered => {}
1197 _ => return,
1198 }
1199
1200 self.collected.insert(type_id);
1201
1202 if let Some(key) = self.types.lookup(type_id) {
1203 self.visit_key(&key);
1204 }
1205
1206 self.guard.leave(type_id);
1207 }
1208
1209 fn visit_key(&mut self, key: &TypeData) {
1210 match key {
1211 TypeData::Intrinsic(_)
1212 | TypeData::Literal(_)
1213 | TypeData::Error
1214 | TypeData::ThisType
1215 | TypeData::BoundParameter(_)
1216 | TypeData::Lazy(_)
1217 | TypeData::Recursive(_)
1218 | TypeData::TypeQuery(_)
1219 | TypeData::UniqueSymbol(_)
1220 | TypeData::ModuleNamespace(_) => {
1221 }
1223 TypeData::NoInfer(inner) => {
1224 self.visit(*inner);
1226 }
1227 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
1228 let shape = self.types.object_shape(*shape_id);
1229 for prop in &shape.properties {
1230 self.visit(prop.type_id);
1231 self.visit(prop.write_type);
1232 }
1233 if let Some(ref idx) = shape.string_index {
1234 self.visit(idx.key_type);
1235 self.visit(idx.value_type);
1236 }
1237 if let Some(ref idx) = shape.number_index {
1238 self.visit(idx.key_type);
1239 self.visit(idx.value_type);
1240 }
1241 }
1242 TypeData::Union(list_id) | TypeData::Intersection(list_id) => {
1243 let members = self.types.type_list(*list_id);
1244 for &member in members.iter() {
1245 self.visit(member);
1246 }
1247 }
1248 TypeData::Array(elem) => {
1249 self.visit(*elem);
1250 }
1251 TypeData::Tuple(list_id) => {
1252 let elements = self.types.tuple_list(*list_id);
1253 for elem in elements.iter() {
1254 self.visit(elem.type_id);
1255 }
1256 }
1257 TypeData::Function(shape_id) => {
1258 let shape = self.types.function_shape(*shape_id);
1259 for param in &shape.params {
1260 self.visit(param.type_id);
1261 }
1262 self.visit(shape.return_type);
1263 if let Some(this_type) = shape.this_type {
1264 self.visit(this_type);
1265 }
1266 if let Some(ref type_predicate) = shape.type_predicate
1267 && let Some(type_id) = type_predicate.type_id
1268 {
1269 self.visit(type_id);
1270 }
1271 for type_param in &shape.type_params {
1272 if let Some(constraint) = type_param.constraint {
1273 self.visit(constraint);
1274 }
1275 if let Some(default) = type_param.default {
1276 self.visit(default);
1277 }
1278 }
1279 }
1280 TypeData::Callable(shape_id) => {
1281 let shape = self.types.callable_shape(*shape_id);
1282 for sig in &shape.call_signatures {
1283 for param in &sig.params {
1284 self.visit(param.type_id);
1285 }
1286 self.visit(sig.return_type);
1287 if let Some(this_type) = sig.this_type {
1288 self.visit(this_type);
1289 }
1290 if let Some(ref type_predicate) = sig.type_predicate
1291 && let Some(type_id) = type_predicate.type_id
1292 {
1293 self.visit(type_id);
1294 }
1295 for type_param in &sig.type_params {
1296 if let Some(constraint) = type_param.constraint {
1297 self.visit(constraint);
1298 }
1299 if let Some(default) = type_param.default {
1300 self.visit(default);
1301 }
1302 }
1303 }
1304 for sig in &shape.construct_signatures {
1305 for param in &sig.params {
1306 self.visit(param.type_id);
1307 }
1308 self.visit(sig.return_type);
1309 if let Some(this_type) = sig.this_type {
1310 self.visit(this_type);
1311 }
1312 if let Some(ref type_predicate) = sig.type_predicate
1313 && let Some(type_id) = type_predicate.type_id
1314 {
1315 self.visit(type_id);
1316 }
1317 for type_param in &sig.type_params {
1318 if let Some(constraint) = type_param.constraint {
1319 self.visit(constraint);
1320 }
1321 if let Some(default) = type_param.default {
1322 self.visit(default);
1323 }
1324 }
1325 }
1326 for prop in &shape.properties {
1327 self.visit(prop.type_id);
1328 self.visit(prop.write_type);
1329 }
1330 if let Some(ref sig) = shape.string_index {
1331 self.visit(sig.key_type);
1332 self.visit(sig.value_type);
1333 }
1334 if let Some(ref sig) = shape.number_index {
1335 self.visit(sig.key_type);
1336 self.visit(sig.value_type);
1337 }
1338 }
1339 TypeData::TypeParameter(info) | TypeData::Infer(info) => {
1340 if let Some(constraint) = info.constraint {
1341 self.visit(constraint);
1342 }
1343 if let Some(default) = info.default {
1344 self.visit(default);
1345 }
1346 }
1347 TypeData::Application(app_id) => {
1348 let app = self.types.type_application(*app_id);
1349 self.visit(app.base);
1350 for &arg in &app.args {
1351 self.visit(arg);
1352 }
1353 }
1354 TypeData::Conditional(cond_id) => {
1355 let cond = self.types.conditional_type(*cond_id);
1356 self.visit(cond.check_type);
1357 self.visit(cond.extends_type);
1358 self.visit(cond.true_type);
1359 self.visit(cond.false_type);
1360 }
1361 TypeData::Mapped(mapped_id) => {
1362 let mapped = self.types.mapped_type(*mapped_id);
1363 if let Some(constraint) = mapped.type_param.constraint {
1364 self.visit(constraint);
1365 }
1366 if let Some(default) = mapped.type_param.default {
1367 self.visit(default);
1368 }
1369 self.visit(mapped.constraint);
1370 self.visit(mapped.template);
1371 if let Some(name_type) = mapped.name_type {
1372 self.visit(name_type);
1373 }
1374 }
1375 TypeData::IndexAccess(obj, idx) => {
1376 self.visit(*obj);
1377 self.visit(*idx);
1378 }
1379 TypeData::TemplateLiteral(list_id) => {
1380 let spans = self.types.template_list(*list_id);
1381 for span in spans.iter() {
1382 if let crate::types::TemplateSpan::Type(type_id) = span {
1383 self.visit(*type_id);
1384 }
1385 }
1386 }
1387 TypeData::KeyOf(inner) | TypeData::ReadonlyType(inner) => {
1388 self.visit(*inner);
1389 }
1390 TypeData::StringIntrinsic { type_arg, .. } => {
1391 self.visit(*type_arg);
1392 }
1393 TypeData::Enum(_def_id, member_type) => {
1394 self.visit(*member_type);
1396 }
1397 }
1398 }
1399}
1400
1401pub fn collect_all_types(types: &dyn TypeDatabase, type_id: TypeId) -> FxHashSet<TypeId> {
1403 let mut collector = RecursiveTypeCollector::new(types);
1404 collector.collect(type_id)
1405}
1406
1407pub fn contains_type_parameters(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1413 contains_type_matching(types, type_id, |key| {
1414 matches!(key, TypeData::TypeParameter(_) | TypeData::Infer(_))
1415 })
1416}
1417
1418pub fn contains_infer_types(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1420 contains_type_matching(types, type_id, |key| matches!(key, TypeData::Infer(_)))
1421}
1422
1423pub fn contains_error_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1425 if type_id == TypeId::ERROR {
1426 return true;
1427 }
1428 contains_type_matching(types, type_id, |key| matches!(key, TypeData::Error))
1429}
1430
1431pub fn contains_this_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1433 contains_type_matching(types, type_id, |key| matches!(key, TypeData::ThisType))
1434}
1435
1436pub fn contains_type_matching<F>(types: &dyn TypeDatabase, type_id: TypeId, predicate: F) -> bool
1438where
1439 F: Fn(&TypeData) -> bool,
1440{
1441 let mut checker = ContainsTypeChecker {
1442 types,
1443 predicate,
1444 memo: FxHashMap::default(),
1445 guard: crate::recursion::RecursionGuard::with_profile(
1446 crate::recursion::RecursionProfile::ShallowTraversal,
1447 ),
1448 };
1449 checker.check(type_id)
1450}
1451
1452struct ContainsTypeChecker<'a, F>
1453where
1454 F: Fn(&TypeData) -> bool,
1455{
1456 types: &'a dyn TypeDatabase,
1457 predicate: F,
1458 memo: FxHashMap<TypeId, bool>,
1459 guard: crate::recursion::RecursionGuard<TypeId>,
1460}
1461
1462impl<'a, F> ContainsTypeChecker<'a, F>
1463where
1464 F: Fn(&TypeData) -> bool,
1465{
1466 fn check(&mut self, type_id: TypeId) -> bool {
1467 if let Some(&cached) = self.memo.get(&type_id) {
1468 return cached;
1469 }
1470
1471 match self.guard.enter(type_id) {
1472 crate::recursion::RecursionResult::Entered => {}
1473 _ => return false,
1474 }
1475
1476 let Some(key) = self.types.lookup(type_id) else {
1477 self.guard.leave(type_id);
1478 return false;
1479 };
1480
1481 if (self.predicate)(&key) {
1482 self.guard.leave(type_id);
1483 self.memo.insert(type_id, true);
1484 return true;
1485 }
1486
1487 let result = self.check_key(&key);
1488
1489 self.guard.leave(type_id);
1490 self.memo.insert(type_id, result);
1491
1492 result
1493 }
1494
1495 fn check_key(&mut self, key: &TypeData) -> bool {
1496 match key {
1497 TypeData::Intrinsic(_)
1498 | TypeData::Literal(_)
1499 | TypeData::Error
1500 | TypeData::ThisType
1501 | TypeData::BoundParameter(_)
1502 | TypeData::Lazy(_)
1503 | TypeData::Recursive(_)
1504 | TypeData::TypeQuery(_)
1505 | TypeData::UniqueSymbol(_)
1506 | TypeData::ModuleNamespace(_) => false,
1507 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
1508 let shape = self.types.object_shape(*shape_id);
1509 shape.properties.iter().any(|p| self.check(p.type_id))
1510 || shape
1511 .string_index
1512 .as_ref()
1513 .is_some_and(|i| self.check(i.value_type))
1514 || shape
1515 .number_index
1516 .as_ref()
1517 .is_some_and(|i| self.check(i.value_type))
1518 }
1519 TypeData::Union(list_id) | TypeData::Intersection(list_id) => {
1520 let members = self.types.type_list(*list_id);
1521 members.iter().any(|&m| self.check(m))
1522 }
1523 TypeData::Array(elem) => self.check(*elem),
1524 TypeData::Tuple(list_id) => {
1525 let elements = self.types.tuple_list(*list_id);
1526 elements.iter().any(|e| self.check(e.type_id))
1527 }
1528 TypeData::Function(shape_id) => {
1529 let shape = self.types.function_shape(*shape_id);
1530 shape.params.iter().any(|p| self.check(p.type_id))
1531 || self.check(shape.return_type)
1532 || shape.this_type.is_some_and(|t| self.check(t))
1533 }
1534 TypeData::Callable(shape_id) => {
1535 let shape = self.types.callable_shape(*shape_id);
1536 shape.call_signatures.iter().any(|s| {
1537 s.params.iter().any(|p| self.check(p.type_id)) || self.check(s.return_type)
1538 }) || shape.construct_signatures.iter().any(|s| {
1539 s.params.iter().any(|p| self.check(p.type_id)) || self.check(s.return_type)
1540 }) || shape.properties.iter().any(|p| self.check(p.type_id))
1541 }
1542 TypeData::TypeParameter(info) | TypeData::Infer(info) => {
1543 info.constraint.is_some_and(|c| self.check(c))
1544 || info.default.is_some_and(|d| self.check(d))
1545 }
1546 TypeData::Application(app_id) => {
1547 let app = self.types.type_application(*app_id);
1548 self.check(app.base) || app.args.iter().any(|&a| self.check(a))
1549 }
1550 TypeData::Conditional(cond_id) => {
1551 let cond = self.types.conditional_type(*cond_id);
1552 self.check(cond.check_type)
1553 || self.check(cond.extends_type)
1554 || self.check(cond.true_type)
1555 || self.check(cond.false_type)
1556 }
1557 TypeData::Mapped(mapped_id) => {
1558 let mapped = self.types.mapped_type(*mapped_id);
1559 mapped.type_param.constraint.is_some_and(|c| self.check(c))
1560 || mapped.type_param.default.is_some_and(|d| self.check(d))
1561 || self.check(mapped.constraint)
1562 || self.check(mapped.template)
1563 || mapped.name_type.is_some_and(|n| self.check(n))
1564 }
1565 TypeData::IndexAccess(obj, idx) => self.check(*obj) || self.check(*idx),
1566 TypeData::TemplateLiteral(list_id) => {
1567 let spans = self.types.template_list(*list_id);
1568 spans.iter().any(|span| {
1569 if let crate::types::TemplateSpan::Type(type_id) = span {
1570 self.check(*type_id)
1571 } else {
1572 false
1573 }
1574 })
1575 }
1576 TypeData::KeyOf(inner) | TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner) => {
1577 self.check(*inner)
1578 }
1579 TypeData::StringIntrinsic { type_arg, .. } => self.check(*type_arg),
1580 TypeData::Enum(_def_id, member_type) => self.check(*member_type),
1581 }
1582 }
1583}
1584
1585pub fn is_literal_type_db(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1591 LiteralTypeChecker::check(types, type_id)
1592}
1593
1594pub fn is_module_namespace_type_db(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1596 matches!(types.lookup(type_id), Some(TypeData::ModuleNamespace(_)))
1597}
1598
1599pub fn is_function_type_db(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1601 FunctionTypeChecker::check(types, type_id)
1602}
1603
1604pub fn is_object_like_type_db(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1606 ObjectTypeChecker::check(types, type_id)
1607}
1608
1609pub fn is_empty_object_type_db(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1611 let checker = EmptyObjectChecker::new(types);
1612 checker.check(type_id)
1613}
1614
1615pub enum ObjectTypeKind {
1621 Object(ObjectShapeId),
1623 ObjectWithIndex(ObjectShapeId),
1625 NotObject,
1627}
1628
1629pub fn classify_object_type(types: &dyn TypeDatabase, type_id: TypeId) -> ObjectTypeKind {
1634 match types.lookup(type_id) {
1635 Some(TypeData::Object(shape_id)) => ObjectTypeKind::Object(shape_id),
1636 Some(TypeData::ObjectWithIndex(shape_id)) => ObjectTypeKind::ObjectWithIndex(shape_id),
1637 _ => ObjectTypeKind::NotObject,
1638 }
1639}
1640
1641struct LiteralTypeChecker;
1647
1648impl LiteralTypeChecker {
1649 fn check(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1650 match types.lookup(type_id) {
1651 Some(TypeData::Literal(_)) => true,
1652 Some(TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner)) => {
1653 Self::check(types, inner)
1654 }
1655 Some(TypeData::TypeParameter(info) | TypeData::Infer(info)) => {
1656 info.constraint.is_some_and(|c| Self::check(types, c))
1657 }
1658 _ => false,
1659 }
1660 }
1661}
1662
1663struct FunctionTypeChecker;
1665
1666impl FunctionTypeChecker {
1667 fn check(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1668 match types.lookup(type_id) {
1669 Some(TypeData::Function(_) | TypeData::Callable(_)) => true,
1670 Some(TypeData::Intersection(members)) => {
1671 let members = types.type_list(members);
1672 members.iter().any(|&member| Self::check(types, member))
1673 }
1674 Some(TypeData::TypeParameter(info) | TypeData::Infer(info)) => {
1675 info.constraint.is_some_and(|c| Self::check(types, c))
1676 }
1677 _ => false,
1678 }
1679 }
1680}
1681
1682struct ObjectTypeChecker;
1684
1685impl ObjectTypeChecker {
1686 fn check(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
1687 match types.lookup(type_id) {
1688 Some(
1689 TypeData::Object(_)
1690 | TypeData::ObjectWithIndex(_)
1691 | TypeData::Array(_)
1692 | TypeData::Tuple(_)
1693 | TypeData::Mapped(_),
1694 ) => true,
1695 Some(TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner)) => {
1696 Self::check(types, inner)
1697 }
1698 Some(TypeData::Intersection(members)) => {
1699 let members = types.type_list(members);
1700 members.iter().all(|&member| Self::check(types, member))
1701 }
1702 Some(TypeData::TypeParameter(info) | TypeData::Infer(info)) => info
1703 .constraint
1704 .is_some_and(|constraint| Self::check(types, constraint)),
1705 _ => false,
1706 }
1707 }
1708}
1709
1710struct EmptyObjectChecker<'a> {
1712 db: &'a dyn TypeDatabase,
1713}
1714
1715impl<'a> EmptyObjectChecker<'a> {
1716 fn new(db: &'a dyn TypeDatabase) -> Self {
1717 Self { db }
1718 }
1719
1720 fn check(&self, type_id: TypeId) -> bool {
1721 match self.db.lookup(type_id) {
1722 Some(TypeData::Object(shape_id)) => {
1723 let shape = self.db.object_shape(shape_id);
1724 shape.properties.is_empty()
1725 }
1726 Some(TypeData::ObjectWithIndex(shape_id)) => {
1727 let shape = self.db.object_shape(shape_id);
1728 shape.properties.is_empty()
1729 && shape.string_index.is_none()
1730 && shape.number_index.is_none()
1731 }
1732 Some(TypeData::ReadonlyType(inner) | TypeData::NoInfer(inner)) => self.check(inner),
1733 Some(TypeData::TypeParameter(info) | TypeData::Infer(info)) => {
1734 info.constraint.is_some_and(|c| self.check(c))
1735 }
1736 _ => false,
1737 }
1738 }
1739}
1740
1741pub struct ConstAssertionVisitor<'a> {
1754 pub db: &'a dyn TypeDatabase,
1756 pub guard: crate::recursion::RecursionGuard<TypeId>,
1758}
1759
1760impl<'a> ConstAssertionVisitor<'a> {
1761 pub fn new(db: &'a dyn TypeDatabase) -> Self {
1763 Self {
1764 db,
1765 guard: crate::recursion::RecursionGuard::with_profile(
1766 crate::recursion::RecursionProfile::ConstAssertion,
1767 ),
1768 }
1769 }
1770
1771 pub fn apply_const_assertion(&mut self, type_id: TypeId) -> TypeId {
1773 match self.guard.enter(type_id) {
1775 crate::recursion::RecursionResult::Entered => {}
1776 _ => return type_id,
1777 }
1778
1779 let result = match self.db.lookup(type_id) {
1780 Some(TypeData::Array(element_type)) => {
1782 let const_element = self.apply_const_assertion(element_type);
1783 let tuple_elem = TupleElement {
1785 type_id: const_element,
1786 name: None,
1787 optional: false,
1788 rest: false,
1789 };
1790 let tuple_type = self.db.tuple(vec![tuple_elem]);
1791 self.db.readonly_type(tuple_type)
1792 }
1793
1794 Some(TypeData::Tuple(list_id)) => {
1796 let elements = self.db.tuple_list(list_id);
1797 let const_elements: Vec<TupleElement> = elements
1798 .iter()
1799 .map(|elem| {
1800 let const_type = self.apply_const_assertion(elem.type_id);
1801 TupleElement {
1802 type_id: const_type,
1803 name: elem.name,
1804 optional: elem.optional,
1805 rest: elem.rest,
1806 }
1807 })
1808 .collect();
1809 let tuple_type = self.db.tuple(const_elements);
1810 self.db.readonly_type(tuple_type)
1811 }
1812
1813 Some(TypeData::Object(shape_id)) => {
1815 let shape = self.db.object_shape(shape_id);
1816 let mut new_props = Vec::with_capacity(shape.properties.len());
1817
1818 for prop in &shape.properties {
1819 let const_prop_type = self.apply_const_assertion(prop.type_id);
1820 let const_write_type = self.apply_const_assertion(prop.write_type);
1821 new_props.push(crate::types::PropertyInfo {
1822 name: prop.name,
1823 type_id: const_prop_type,
1824 write_type: const_write_type,
1825 optional: prop.optional,
1826 readonly: true, is_method: prop.is_method,
1828 visibility: prop.visibility,
1829 parent_id: prop.parent_id,
1830 });
1831 }
1832
1833 self.db.object(new_props)
1834 }
1835
1836 Some(TypeData::ObjectWithIndex(shape_id)) => {
1838 let shape = self.db.object_shape(shape_id);
1839 let mut new_props = Vec::with_capacity(shape.properties.len());
1840
1841 for prop in &shape.properties {
1842 let const_prop_type = self.apply_const_assertion(prop.type_id);
1843 let const_write_type = self.apply_const_assertion(prop.write_type);
1844 new_props.push(crate::types::PropertyInfo {
1845 name: prop.name,
1846 type_id: const_prop_type,
1847 write_type: const_write_type,
1848 optional: prop.optional,
1849 readonly: true, is_method: prop.is_method,
1851 visibility: prop.visibility,
1852 parent_id: prop.parent_id,
1853 });
1854 }
1855
1856 let string_index =
1858 shape
1859 .string_index
1860 .as_ref()
1861 .map(|idx| crate::types::IndexSignature {
1862 key_type: idx.key_type,
1863 value_type: self.apply_const_assertion(idx.value_type),
1864 readonly: true,
1865 });
1866
1867 let number_index =
1868 shape
1869 .number_index
1870 .as_ref()
1871 .map(|idx| crate::types::IndexSignature {
1872 key_type: idx.key_type,
1873 value_type: self.apply_const_assertion(idx.value_type),
1874 readonly: true,
1875 });
1876
1877 let mut new_shape = (*shape).clone();
1878 new_shape.properties = new_props;
1879 new_shape.string_index = string_index;
1880 new_shape.number_index = number_index;
1881
1882 self.db.object_with_index(new_shape)
1883 }
1884
1885 Some(TypeData::ReadonlyType(inner)) => {
1887 let const_inner = self.apply_const_assertion(inner);
1888 self.db.readonly_type(const_inner)
1889 }
1890
1891 Some(TypeData::Union(list_id)) => {
1893 let members = self.db.type_list(list_id);
1894 let const_members: Vec<TypeId> = members
1895 .iter()
1896 .map(|&m| self.apply_const_assertion(m))
1897 .collect();
1898 self.db.union(const_members)
1899 }
1900
1901 Some(TypeData::Intersection(list_id)) => {
1903 let members = self.db.type_list(list_id);
1904 let const_members: Vec<TypeId> = members
1905 .iter()
1906 .map(|&m| self.apply_const_assertion(m))
1907 .collect();
1908 self.db.intersection(const_members)
1909 }
1910
1911 _ => type_id,
1913 };
1914
1915 self.guard.leave(type_id);
1916 result
1917 }
1918}