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_def_id(db: &dyn TypeDatabase, type_id: TypeId) -> Option<crate::def::DefId> {
171 match db.lookup(type_id) {
172 Some(TypeData::Lazy(def_id)) => Some(def_id),
173 _ => None,
174 }
175}
176
177pub fn get_type_identity(
180 db: &dyn TypeDatabase,
181 type_id: TypeId,
182) -> (Option<crate::types::SymbolRef>, Option<crate::def::DefId>) {
183 match db.lookup(type_id) {
184 Some(TypeData::Lazy(def_id)) => (None, Some(def_id)),
185 _ => (None, None),
186 }
187}
188
189pub fn get_enum_components(
195 db: &dyn TypeDatabase,
196 type_id: TypeId,
197) -> Option<(crate::def::DefId, TypeId)> {
198 match db.lookup(type_id) {
199 Some(TypeData::Enum(def_id, member_type)) => Some((def_id, member_type)),
200 _ => None,
201 }
202}
203
204pub fn get_mapped_type_id(
206 db: &dyn TypeDatabase,
207 type_id: TypeId,
208) -> Option<crate::types::MappedTypeId> {
209 match db.lookup(type_id) {
210 Some(TypeData::Mapped(mapped_id)) => Some(mapped_id),
211 _ => None,
212 }
213}
214
215pub fn get_conditional_type_id(
217 db: &dyn TypeDatabase,
218 type_id: TypeId,
219) -> Option<crate::types::ConditionalTypeId> {
220 match db.lookup(type_id) {
221 Some(TypeData::Conditional(cond_id)) => Some(cond_id),
222 _ => None,
223 }
224}
225
226pub fn get_keyof_inner(db: &dyn TypeDatabase, type_id: TypeId) -> Option<TypeId> {
228 match db.lookup(type_id) {
229 Some(TypeData::KeyOf(inner)) => Some(inner),
230 _ => None,
231 }
232}
233
234#[derive(Debug, Clone)]
241pub enum SymbolResolutionTraversalKind {
242 Application {
244 app_id: crate::types::TypeApplicationId,
245 base: TypeId,
246 args: Vec<TypeId>,
247 },
248 Lazy(crate::def::DefId),
250 TypeParameter {
252 constraint: Option<TypeId>,
253 default: Option<TypeId>,
254 },
255 Members(Vec<TypeId>),
257 Function(crate::types::FunctionShapeId),
259 Callable(crate::types::CallableShapeId),
261 Object(crate::types::ObjectShapeId),
263 Array(TypeId),
265 Tuple(crate::types::TupleListId),
267 Conditional(crate::types::ConditionalTypeId),
269 Mapped(crate::types::MappedTypeId),
271 Readonly(TypeId),
273 IndexAccess { object: TypeId, index: TypeId },
275 KeyOf(TypeId),
277 Terminal,
279}
280
281pub fn classify_for_symbol_resolution_traversal(
283 db: &dyn TypeDatabase,
284 type_id: TypeId,
285) -> SymbolResolutionTraversalKind {
286 let Some(key) = db.lookup(type_id) else {
287 return SymbolResolutionTraversalKind::Terminal;
288 };
289
290 match key {
291 TypeData::Application(app_id) => {
292 let app = db.type_application(app_id);
293 SymbolResolutionTraversalKind::Application {
294 app_id,
295 base: app.base,
296 args: app.args.clone(),
297 }
298 }
299 TypeData::Lazy(def_id) => SymbolResolutionTraversalKind::Lazy(def_id),
300 TypeData::TypeParameter(param) | TypeData::Infer(param) => {
301 SymbolResolutionTraversalKind::TypeParameter {
302 constraint: param.constraint,
303 default: param.default,
304 }
305 }
306 TypeData::Union(members_id) | TypeData::Intersection(members_id) => {
307 let members = db.type_list(members_id);
308 SymbolResolutionTraversalKind::Members(members.to_vec())
309 }
310 TypeData::Function(shape_id) => SymbolResolutionTraversalKind::Function(shape_id),
311 TypeData::Callable(shape_id) => SymbolResolutionTraversalKind::Callable(shape_id),
312 TypeData::Object(shape_id) | TypeData::ObjectWithIndex(shape_id) => {
313 SymbolResolutionTraversalKind::Object(shape_id)
314 }
315 TypeData::Array(elem) => SymbolResolutionTraversalKind::Array(elem),
316 TypeData::Tuple(elems_id) => SymbolResolutionTraversalKind::Tuple(elems_id),
317 TypeData::Conditional(cond_id) => SymbolResolutionTraversalKind::Conditional(cond_id),
318 TypeData::Mapped(mapped_id) => SymbolResolutionTraversalKind::Mapped(mapped_id),
319 TypeData::ReadonlyType(inner) => SymbolResolutionTraversalKind::Readonly(inner),
320 TypeData::IndexAccess(obj, idx) => SymbolResolutionTraversalKind::IndexAccess {
321 object: obj,
322 index: idx,
323 },
324 TypeData::KeyOf(inner) => SymbolResolutionTraversalKind::KeyOf(inner),
325 _ => SymbolResolutionTraversalKind::Terminal,
326 }
327}
328
329#[derive(Debug, Clone)]
339pub enum InterfaceMergeKind {
340 Callable(crate::types::CallableShapeId),
342 Object(crate::types::ObjectShapeId),
344 ObjectWithIndex(crate::types::ObjectShapeId),
346 Intersection,
348 Other,
350}
351
352pub fn classify_for_interface_merge(db: &dyn TypeDatabase, type_id: TypeId) -> InterfaceMergeKind {
384 let Some(key) = db.lookup(type_id) else {
385 return InterfaceMergeKind::Other;
386 };
387
388 match key {
389 TypeData::Callable(shape_id) => InterfaceMergeKind::Callable(shape_id),
390 TypeData::Object(shape_id) => InterfaceMergeKind::Object(shape_id),
391 TypeData::ObjectWithIndex(shape_id) => InterfaceMergeKind::ObjectWithIndex(shape_id),
392 TypeData::Intersection(_) => InterfaceMergeKind::Intersection,
393 TypeData::BoundParameter(_)
395 | TypeData::Intrinsic(_)
396 | TypeData::Literal(_)
397 | TypeData::Union(_)
398 | TypeData::Array(_)
399 | TypeData::Tuple(_)
400 | TypeData::Function(_)
401 | TypeData::TypeParameter(_)
402 | TypeData::Infer(_)
403 | TypeData::Lazy(_)
404 | TypeData::Recursive(_)
405 | TypeData::Application(_)
406 | TypeData::Conditional(_)
407 | TypeData::Mapped(_)
408 | TypeData::IndexAccess(_, _)
409 | TypeData::KeyOf(_)
410 | TypeData::TemplateLiteral(_)
411 | TypeData::UniqueSymbol(_)
412 | TypeData::ThisType
413 | TypeData::TypeQuery(_)
414 | TypeData::ReadonlyType(_)
415 | TypeData::NoInfer(_)
416 | TypeData::StringIntrinsic { .. }
417 | TypeData::ModuleNamespace(_)
418 | TypeData::Error
419 | TypeData::Enum(_, _) => InterfaceMergeKind::Other,
420 }
421}
422
423#[derive(Debug, Clone)]
432pub enum AugmentationTargetKind {
433 Object(crate::types::ObjectShapeId),
435 ObjectWithIndex(crate::types::ObjectShapeId),
437 Callable(crate::types::CallableShapeId),
439 Other,
441}
442
443pub fn classify_for_augmentation(db: &dyn TypeDatabase, type_id: TypeId) -> AugmentationTargetKind {
448 let Some(key) = db.lookup(type_id) else {
449 return AugmentationTargetKind::Other;
450 };
451
452 match key {
453 TypeData::Object(shape_id) => AugmentationTargetKind::Object(shape_id),
454 TypeData::ObjectWithIndex(shape_id) => AugmentationTargetKind::ObjectWithIndex(shape_id),
455 TypeData::Callable(shape_id) => AugmentationTargetKind::Callable(shape_id),
456 _ => AugmentationTargetKind::Other,
458 }
459}