1use crate::{TypeData, TypeDatabase, TypeId};
14
15#[derive(Debug, Clone)]
21pub enum ExcessPropertiesKind {
22 Object(crate::types::ObjectShapeId),
24 ObjectWithIndex(crate::types::ObjectShapeId),
26 Union(Vec<TypeId>),
28 Intersection(Vec<TypeId>),
30 NotObject,
32}
33
34pub fn classify_for_excess_properties(
36 db: &dyn TypeDatabase,
37 type_id: TypeId,
38) -> ExcessPropertiesKind {
39 let Some(key) = db.lookup(type_id) else {
40 return ExcessPropertiesKind::NotObject;
41 };
42
43 match key {
44 TypeData::Object(shape_id) => ExcessPropertiesKind::Object(shape_id),
45 TypeData::ObjectWithIndex(shape_id) => ExcessPropertiesKind::ObjectWithIndex(shape_id),
46 TypeData::Union(list_id) => {
47 let members = db.type_list(list_id);
48 ExcessPropertiesKind::Union(members.to_vec())
49 }
50 TypeData::Intersection(list_id) => {
51 let members = db.type_list(list_id);
52 ExcessPropertiesKind::Intersection(members.to_vec())
53 }
54 _ => ExcessPropertiesKind::NotObject,
55 }
56}
57
58#[derive(Debug, Clone)]
64pub enum ConstructorAccessKind {
65 SymbolRef(crate::types::SymbolRef),
67 Application(crate::types::TypeApplicationId),
69 Other,
71}
72
73pub fn classify_for_constructor_access(
75 db: &dyn TypeDatabase,
76 type_id: TypeId,
77) -> ConstructorAccessKind {
78 let Some(key) = db.lookup(type_id) else {
79 return ConstructorAccessKind::Other;
80 };
81
82 match key {
83 TypeData::TypeQuery(sym_ref) => ConstructorAccessKind::SymbolRef(sym_ref),
84 TypeData::Application(app_id) => ConstructorAccessKind::Application(app_id),
85 _ => ConstructorAccessKind::Other,
86 }
87}
88
89#[derive(Debug, Clone)]
95pub enum AssignabilityEvalKind {
96 Application,
98 NeedsEnvEval,
100 Resolved,
102}
103
104pub fn classify_for_assignability_eval(
106 db: &dyn TypeDatabase,
107 type_id: TypeId,
108) -> AssignabilityEvalKind {
109 let Some(key) = db.lookup(type_id) else {
110 return AssignabilityEvalKind::Resolved;
111 };
112
113 match key {
114 TypeData::Application(_) | TypeData::Lazy(_) => AssignabilityEvalKind::Application,
115 TypeData::IndexAccess(_, _)
116 | TypeData::KeyOf(_)
117 | TypeData::Mapped(_)
118 | TypeData::Conditional(_) => AssignabilityEvalKind::NeedsEnvEval,
119 _ => AssignabilityEvalKind::Resolved,
120 }
121}
122
123#[derive(Debug, Clone)]
129pub enum BindingElementTypeKind {
130 Array(TypeId),
132 Tuple(crate::types::TupleListId),
134 Object(crate::types::ObjectShapeId),
136 Other,
138}
139
140pub fn classify_for_binding_element(
142 db: &dyn TypeDatabase,
143 type_id: TypeId,
144) -> BindingElementTypeKind {
145 let Some(key) = db.lookup(type_id) else {
146 return BindingElementTypeKind::Other;
147 };
148
149 match key {
150 TypeData::Array(elem) => BindingElementTypeKind::Array(elem),
151 TypeData::Tuple(list_id) => BindingElementTypeKind::Tuple(list_id),
152 TypeData::Object(shape_id) => BindingElementTypeKind::Object(shape_id),
153 _ => BindingElementTypeKind::Other,
154 }
155}
156
157pub fn get_lazy_def_id(db: &dyn TypeDatabase, type_id: TypeId) -> Option<crate::def::DefId> {
163 match db.lookup(type_id) {
164 Some(TypeData::Lazy(def_id)) => Some(def_id),
165 _ => None,
166 }
167}
168
169pub fn get_type_identity(
172 db: &dyn TypeDatabase,
173 type_id: TypeId,
174) -> (Option<crate::types::SymbolRef>, Option<crate::def::DefId>) {
175 match db.lookup(type_id) {
176 Some(TypeData::Lazy(def_id)) => (None, Some(def_id)),
177 _ => (None, None),
178 }
179}
180
181pub fn get_enum_components(
187 db: &dyn TypeDatabase,
188 type_id: TypeId,
189) -> Option<(crate::def::DefId, TypeId)> {
190 match db.lookup(type_id) {
191 Some(TypeData::Enum(def_id, member_type)) => Some((def_id, member_type)),
192 _ => None,
193 }
194}
195
196pub fn get_mapped_type_id(
198 db: &dyn TypeDatabase,
199 type_id: TypeId,
200) -> Option<crate::types::MappedTypeId> {
201 match db.lookup(type_id) {
202 Some(TypeData::Mapped(mapped_id)) => Some(mapped_id),
203 _ => None,
204 }
205}
206
207pub fn get_conditional_type_id(
209 db: &dyn TypeDatabase,
210 type_id: TypeId,
211) -> Option<crate::types::ConditionalTypeId> {
212 match db.lookup(type_id) {
213 Some(TypeData::Conditional(cond_id)) => Some(cond_id),
214 _ => None,
215 }
216}
217
218pub fn get_keyof_type(db: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
220 match db.lookup(type_id) {
221 Some(TypeData::KeyOf(inner)) => Some(inner),
222 _ => None,
223 }
224}
225
226#[derive(Debug, Clone)]
233pub enum SymbolResolutionTraversalKind {
234 Application {
236 app_id: crate::types::TypeApplicationId,
237 base: TypeId,
238 args: Vec<TypeId>,
239 },
240 Lazy(crate::def::DefId),
242 TypeParameter {
244 constraint: Option<TypeId>,
245 default: Option<TypeId>,
246 },
247 Members(Vec<TypeId>),
249 Function(crate::types::FunctionShapeId),
251 Callable(crate::types::CallableShapeId),
253 Object(crate::types::ObjectShapeId),
255 Array(TypeId),
257 Tuple(crate::types::TupleListId),
259 Conditional(crate::types::ConditionalTypeId),
261 Mapped(crate::types::MappedTypeId),
263 Readonly(TypeId),
265 IndexAccess { object: TypeId, index: TypeId },
267 KeyOf(TypeId),
269 Terminal,
271}
272
273pub fn classify_for_symbol_resolution_traversal(
275 db: &dyn TypeDatabase,
276 type_id: TypeId,
277) -> SymbolResolutionTraversalKind {
278 let Some(key) = db.lookup(type_id) else {
279 return SymbolResolutionTraversalKind::Terminal;
280 };
281
282 match key {
283 TypeData::Application(app_id) => {
284 let app = db.type_application(app_id);
285 SymbolResolutionTraversalKind::Application {
286 app_id,
287 base: app.base,
288 args: app.args.clone(),
289 }
290 }
291 TypeData::Lazy(def_id) => SymbolResolutionTraversalKind::Lazy(def_id),
292 TypeData::TypeParameter(param) | TypeData::Infer(param) => {
293 SymbolResolutionTraversalKind::TypeParameter {
294 constraint: param.constraint,
295 default: param.default,
296 }
297 }
298 TypeData::Union(members_id) | TypeData::Intersection(members_id) => {
299 let members = db.type_list(members_id);
300 SymbolResolutionTraversalKind::Members(members.to_vec())
301 }
302 TypeData::Function(shape_id) => SymbolResolutionTraversalKind::Function(shape_id),
303 TypeData::Callable(shape_id) => SymbolResolutionTraversalKind::Callable(shape_id),
304 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
305 SymbolResolutionTraversalKind::Object(shape_id)
306 }
307 TypeData::Array(elem) => SymbolResolutionTraversalKind::Array(elem),
308 TypeData::Tuple(elems_id) => SymbolResolutionTraversalKind::Tuple(elems_id),
309 TypeData::Conditional(cond_id) => SymbolResolutionTraversalKind::Conditional(cond_id),
310 TypeData::Mapped(mapped_id) => SymbolResolutionTraversalKind::Mapped(mapped_id),
311 TypeData::ReadonlyType(inner) => SymbolResolutionTraversalKind::Readonly(inner),
312 TypeData::IndexAccess(obj, idx) => SymbolResolutionTraversalKind::IndexAccess {
313 object: obj,
314 index: idx,
315 },
316 TypeData::KeyOf(inner) => SymbolResolutionTraversalKind::KeyOf(inner),
317 _ => SymbolResolutionTraversalKind::Terminal,
318 }
319}
320
321#[derive(Debug, Clone)]
331pub enum InterfaceMergeKind {
332 Callable(crate::types::CallableShapeId),
334 Object(crate::types::ObjectShapeId),
336 ObjectWithIndex(crate::types::ObjectShapeId),
338 Intersection,
340 Other,
342}
343
344pub fn classify_for_interface_merge(db: &dyn TypeDatabase, type_id: TypeId) -> InterfaceMergeKind {
376 let Some(key) = db.lookup(type_id) else {
377 return InterfaceMergeKind::Other;
378 };
379
380 match key {
381 TypeData::Callable(shape_id) => InterfaceMergeKind::Callable(shape_id),
382 TypeData::Object(shape_id) => InterfaceMergeKind::Object(shape_id),
383 TypeData::ObjectWithIndex(shape_id) => InterfaceMergeKind::ObjectWithIndex(shape_id),
384 TypeData::Intersection(_) => InterfaceMergeKind::Intersection,
385 TypeData::BoundParameter(_)
387 | TypeData::Intrinsic(_)
388 | TypeData::Literal(_)
389 | TypeData::Union(_)
390 | TypeData::Array(_)
391 | TypeData::Tuple(_)
392 | TypeData::Function(_)
393 | TypeData::TypeParameter(_)
394 | TypeData::Infer(_)
395 | TypeData::Lazy(_)
396 | TypeData::Recursive(_)
397 | TypeData::Application(_)
398 | TypeData::Conditional(_)
399 | TypeData::Mapped(_)
400 | TypeData::IndexAccess(_, _)
401 | TypeData::KeyOf(_)
402 | TypeData::TemplateLiteral(_)
403 | TypeData::UniqueSymbol(_)
404 | TypeData::ThisType
405 | TypeData::TypeQuery(_)
406 | TypeData::ReadonlyType(_)
407 | TypeData::NoInfer(_)
408 | TypeData::StringIntrinsic { .. }
409 | TypeData::ModuleNamespace(_)
410 | TypeData::Error
411 | TypeData::Enum(_, _) => InterfaceMergeKind::Other,
412 }
413}
414
415#[derive(Debug, Clone)]
424pub enum AugmentationTargetKind {
425 Object(crate::types::ObjectShapeId),
427 ObjectWithIndex(crate::types::ObjectShapeId),
429 Callable(crate::types::CallableShapeId),
431 Other,
433}
434
435pub fn classify_for_augmentation(db: &dyn TypeDatabase, type_id: TypeId) -> AugmentationTargetKind {
440 let Some(key) = db.lookup(type_id) else {
441 return AugmentationTargetKind::Other;
442 };
443
444 match key {
445 TypeData::Object(shape_id) => AugmentationTargetKind::Object(shape_id),
446 TypeData::ObjectWithIndex(shape_id) => AugmentationTargetKind::ObjectWithIndex(shape_id),
447 TypeData::Callable(shape_id) => AugmentationTargetKind::Callable(shape_id),
448 _ => AugmentationTargetKind::Other,
450 }
451}