1use crate::def::DefId;
8use crate::types::{
9 CallableShapeId, ConditionalTypeId, FunctionShapeId, IntrinsicKind, LiteralValue, MappedTypeId,
10 ObjectShapeId, OrderedFloat, StringIntrinsicKind, TemplateLiteralId, TupleListId,
11 TypeApplicationId, TypeListId, TypeParamInfo,
12};
13use crate::visitor::TypeVisitor;
14use crate::{SymbolRef, TypeData, TypeDatabase, TypeId};
15use tsz_common::interner::Atom;
16
17struct TypeDataDataVisitor<F, T>
18where
19 F: Fn(&TypeData) -> Option<T>,
20{
21 extractor: F,
22}
23
24impl<F, T> TypeDataDataVisitor<F, T>
25where
26 F: Fn(&TypeData) -> Option<T>,
27{
28 const fn new(extractor: F) -> Self {
29 Self { extractor }
30 }
31}
32
33impl<F, T> TypeVisitor for TypeDataDataVisitor<F, T>
34where
35 F: Fn(&TypeData) -> Option<T>,
36{
37 type Output = Option<T>;
38
39 fn visit_type_key(&mut self, _types: &dyn TypeDatabase, type_key: &TypeData) -> Self::Output {
40 (self.extractor)(type_key)
41 }
42
43 fn visit_intrinsic(&mut self, _kind: IntrinsicKind) -> Self::Output {
44 Self::default_output()
45 }
46
47 fn visit_literal(&mut self, _value: &LiteralValue) -> Self::Output {
48 Self::default_output()
49 }
50
51 fn default_output() -> Self::Output {
52 None
53 }
54}
55
56fn extract_type_data<T, F>(types: &dyn TypeDatabase, type_id: TypeId, extractor: F) -> Option<T>
57where
58 F: Fn(&TypeData) -> Option<T>,
59{
60 let mut visitor = TypeDataDataVisitor::new(extractor);
61 visitor.visit_type(types, type_id)
62}
63
64pub fn union_list_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeListId> {
66 extract_type_data(types, type_id, |key| match key {
67 TypeData::Union(list_id) => Some(*list_id),
68 _ => None,
69 })
70}
71
72pub fn intersection_list_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeListId> {
74 extract_type_data(types, type_id, |key| match key {
75 TypeData::Intersection(list_id) => Some(*list_id),
76 _ => None,
77 })
78}
79
80pub fn object_shape_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<ObjectShapeId> {
82 extract_type_data(types, type_id, |key| match key {
83 TypeData::Object(shape_id) => Some(*shape_id),
84 _ => None,
85 })
86}
87
88pub fn object_with_index_shape_id(
90 types: &dyn TypeDatabase,
91 type_id: TypeId,
92) -> Option<ObjectShapeId> {
93 extract_type_data(types, type_id, |key| match key {
94 TypeData::ObjectWithIndex(shape_id) => Some(*shape_id),
95 _ => None,
96 })
97}
98
99pub fn array_element_type(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
101 extract_type_data(types, type_id, |key| match key {
102 TypeData::Array(element) => Some(*element),
103 _ => None,
104 })
105}
106
107pub fn tuple_list_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TupleListId> {
109 extract_type_data(types, type_id, |key| match key {
110 TypeData::Tuple(list_id) => Some(*list_id),
111 _ => None,
112 })
113}
114
115pub fn intrinsic_kind(types: &dyn TypeDatabase, type_id: TypeId) -> Option<IntrinsicKind> {
117 extract_type_data(types, type_id, |key| match key {
118 TypeData::Intrinsic(kind) => Some(*kind),
119 _ => None,
120 })
121}
122
123pub fn literal_value(types: &dyn TypeDatabase, type_id: TypeId) -> Option<LiteralValue> {
125 extract_type_data(types, type_id, |key| match key {
126 TypeData::Literal(value) => Some(value.clone()),
127 _ => None,
128 })
129}
130
131pub fn literal_string(types: &dyn TypeDatabase, type_id: TypeId) -> Option<Atom> {
133 match literal_value(types, type_id) {
134 Some(LiteralValue::String(atom)) => Some(atom),
135 _ => None,
136 }
137}
138
139pub fn literal_number(types: &dyn TypeDatabase, type_id: TypeId) -> Option<OrderedFloat> {
141 match literal_value(types, type_id) {
142 Some(LiteralValue::Number(value)) => Some(value),
143 _ => None,
144 }
145}
146
147pub fn template_literal_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TemplateLiteralId> {
149 extract_type_data(types, type_id, |key| match key {
150 TypeData::TemplateLiteral(list_id) => Some(*list_id),
151 _ => None,
152 })
153}
154
155pub fn type_param_info(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeParamInfo> {
157 extract_type_data(types, type_id, |key| match key {
158 TypeData::TypeParameter(info) | TypeData::Infer(info) => Some(info.clone()),
159 _ => None,
160 })
161}
162
163pub fn ref_symbol(types: &dyn TypeDatabase, type_id: TypeId) -> Option<SymbolRef> {
165 extract_type_data(types, type_id, |key| match key {
166 TypeData::Lazy(_def_id) => {
167 None
171 }
172 _ => None,
173 })
174}
175
176pub fn lazy_def_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<DefId> {
178 extract_type_data(types, type_id, |key| match key {
179 TypeData::Lazy(def_id) => Some(*def_id),
180 _ => None,
181 })
182}
183
184pub fn bound_parameter_index(types: &dyn TypeDatabase, type_id: TypeId) -> Option<u32> {
186 extract_type_data(types, type_id, |key| match key {
187 TypeData::BoundParameter(index) => Some(*index),
188 _ => None,
189 })
190}
191
192pub fn recursive_index(types: &dyn TypeDatabase, type_id: TypeId) -> Option<u32> {
194 extract_type_data(types, type_id, |key| match key {
195 TypeData::Recursive(index) => Some(*index),
196 _ => None,
197 })
198}
199
200pub fn is_enum_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
202 matches!(types.lookup(type_id), Some(TypeData::Enum(_, _)))
203}
204
205pub fn enum_components(types: &dyn TypeDatabase, type_id: TypeId) -> Option<(DefId, TypeId)> {
211 extract_type_data(types, type_id, |key| match key {
212 TypeData::Enum(def_id, member_type) => Some((*def_id, *member_type)),
213 _ => None,
214 })
215}
216
217pub fn application_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeApplicationId> {
219 extract_type_data(types, type_id, |key| match key {
220 TypeData::Application(app_id) => Some(*app_id),
221 _ => None,
222 })
223}
224
225pub fn mapped_type_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<MappedTypeId> {
227 extract_type_data(types, type_id, |key| match key {
228 TypeData::Mapped(mapped_id) => Some(*mapped_id),
229 _ => None,
230 })
231}
232
233pub fn conditional_type_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<ConditionalTypeId> {
235 extract_type_data(types, type_id, |key| match key {
236 TypeData::Conditional(cond_id) => Some(*cond_id),
237 _ => None,
238 })
239}
240
241pub fn index_access_parts(types: &dyn TypeDatabase, type_id: TypeId) -> Option<(TypeId, TypeId)> {
243 extract_type_data(types, type_id, |key| match key {
244 TypeData::IndexAccess(object_type, index_type) => Some((*object_type, *index_type)),
245 _ => None,
246 })
247}
248
249pub fn type_query_symbol(types: &dyn TypeDatabase, type_id: TypeId) -> Option<SymbolRef> {
251 extract_type_data(types, type_id, |key| match key {
252 TypeData::TypeQuery(sym_ref) => Some(*sym_ref),
253 _ => None,
254 })
255}
256
257pub fn keyof_inner_type(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
259 extract_type_data(types, type_id, |key| match key {
260 TypeData::KeyOf(inner) => Some(*inner),
261 _ => None,
262 })
263}
264
265pub fn readonly_inner_type(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
267 extract_type_data(types, type_id, |key| match key {
268 TypeData::ReadonlyType(inner) => Some(*inner),
269 _ => None,
270 })
271}
272
273pub fn no_infer_inner_type(types: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
275 extract_type_data(types, type_id, |key| match key {
276 TypeData::NoInfer(inner) => Some(*inner),
277 _ => None,
278 })
279}
280
281pub fn string_intrinsic_components(
283 types: &dyn TypeDatabase,
284 type_id: TypeId,
285) -> Option<(StringIntrinsicKind, TypeId)> {
286 extract_type_data(types, type_id, |key| match key {
287 TypeData::StringIntrinsic { kind, type_arg } => Some((*kind, *type_arg)),
288 _ => None,
289 })
290}
291
292pub fn unique_symbol_ref(types: &dyn TypeDatabase, type_id: TypeId) -> Option<SymbolRef> {
294 extract_type_data(types, type_id, |key| match key {
295 TypeData::UniqueSymbol(sym_ref) => Some(*sym_ref),
296 _ => None,
297 })
298}
299
300pub fn module_namespace_symbol_ref(types: &dyn TypeDatabase, type_id: TypeId) -> Option<SymbolRef> {
302 extract_type_data(types, type_id, |key| match key {
303 TypeData::ModuleNamespace(sym_ref) => Some(*sym_ref),
304 _ => None,
305 })
306}
307
308pub fn is_this_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
310 extract_type_data(types, type_id, |key| match key {
311 TypeData::ThisType => Some(true),
312 _ => None,
313 })
314 .unwrap_or(false)
315}
316
317pub fn is_error_type(types: &dyn TypeDatabase, type_id: TypeId) -> bool {
319 extract_type_data(types, type_id, |key| match key {
320 TypeData::Error => Some(true),
321 _ => None,
322 })
323 .unwrap_or(false)
324}
325
326pub fn function_shape_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<FunctionShapeId> {
328 extract_type_data(types, type_id, |key| match key {
329 TypeData::Function(shape_id) => Some(*shape_id),
330 _ => None,
331 })
332}
333
334pub fn callable_shape_id(types: &dyn TypeDatabase, type_id: TypeId) -> Option<CallableShapeId> {
336 extract_type_data(types, type_id, |key| match key {
337 TypeData::Callable(shape_id) => Some(*shape_id),
338 _ => None,
339 })
340}