tsz_solver/evaluation/evaluate_rules/
keyof.rs1use crate::TypeDatabase;
6use crate::relations::subtype::TypeResolver;
7use crate::types::{IntrinsicKind, LiteralValue, TupleElement, TypeData, TypeId, TypeListId};
8use rustc_hash::FxHashSet;
9use tsz_common::interner::Atom;
10
11use super::super::evaluate::{
12 ARRAY_METHODS_RETURN_ANY, ARRAY_METHODS_RETURN_BOOLEAN, ARRAY_METHODS_RETURN_NUMBER,
13 ARRAY_METHODS_RETURN_STRING, ARRAY_METHODS_RETURN_VOID, TypeEvaluator,
14};
15
16pub(crate) struct KeyofKeySet {
18 pub has_string: bool,
19 pub has_number: bool,
20 pub has_symbol: bool,
21 pub string_literals: FxHashSet<Atom>,
22}
23
24impl KeyofKeySet {
25 pub fn new() -> Self {
26 Self {
27 has_string: false,
28 has_number: false,
29 has_symbol: false,
30 string_literals: FxHashSet::default(),
31 }
32 }
33
34 pub fn insert_type(&mut self, interner: &dyn TypeDatabase, type_id: TypeId) -> bool {
35 let Some(key) = interner.lookup(type_id) else {
36 return false;
37 };
38
39 match key {
40 TypeData::Union(members) => {
41 let members = interner.type_list(members);
42 members
43 .iter()
44 .all(|&member| self.insert_type(interner, member))
45 }
46 TypeData::Intrinsic(kind) => match kind {
47 IntrinsicKind::String => {
48 self.has_string = true;
49 true
50 }
51 IntrinsicKind::Number => {
52 self.has_number = true;
53 true
54 }
55 IntrinsicKind::Symbol => {
56 self.has_symbol = true;
57 true
58 }
59 IntrinsicKind::Never => true,
60 _ => false,
61 },
62 TypeData::Literal(LiteralValue::String(atom)) => {
63 self.string_literals.insert(atom);
64 true
65 }
66 _ => false,
67 }
68 }
69}
70
71impl<'a, R: TypeResolver> TypeEvaluator<'a, R> {
72 fn recurse_keyof(&mut self, operand: TypeId) -> TypeId {
75 let keyof = self.interner().keyof(operand);
76 self.evaluate(keyof)
77 }
78
79 pub fn evaluate_keyof(&mut self, operand: TypeId) -> TypeId {
81 if let Some(TypeData::TemplateLiteral(_)) = self.interner().lookup(operand) {
85 return self.apparent_primitive_keyof(IntrinsicKind::String);
86 }
87
88 if let Some(TypeData::Union(members)) = self.interner().lookup(operand) {
93 let member_list = self.interner().type_list(members);
94
95 let mut key_types: Vec<TypeId> = Vec::with_capacity(member_list.len());
97 for &member in member_list.iter() {
98 key_types.push(self.recurse_keyof(member));
99 }
100
101 if let Some(intersection) = self.intersect_keyof_sets(&key_types) {
104 intersection
105 } else {
106 self.interner().intersection(key_types)
108 }
109 } else {
110 let evaluated_operand = self.evaluate(operand);
112
113 let key = match self.interner().lookup(evaluated_operand) {
114 Some(k) => k,
115 None => return TypeId::NEVER,
116 };
117
118 match key {
119 TypeData::Mapped(mapped_id) => {
120 let mapped = self.interner().mapped_type(mapped_id);
121 if let Some(name_type) = mapped.name_type {
122 self.evaluate(name_type)
123 } else {
124 self.evaluate(mapped.constraint)
125 }
126 }
127 TypeData::ReadonlyType(inner) => self.recurse_keyof(inner),
128 TypeData::TypeQuery(sym) => {
129 let resolved = self.resolver().resolve_symbol_ref(sym, self.interner());
131 if let Some(resolved) = resolved {
132 self.recurse_keyof(resolved)
133 } else {
134 TypeId::ERROR
135 }
136 }
137 TypeData::TypeParameter(param) | TypeData::Infer(param) => {
138 if let Some(constraint) = param.constraint {
139 if constraint == evaluated_operand {
140 self.interner().keyof(operand)
141 } else {
142 self.recurse_keyof(constraint)
143 }
144 } else {
145 self.interner().keyof(operand)
146 }
147 }
148 TypeData::Object(shape_id) => {
149 let shape = self.interner().object_shape(shape_id);
150 if shape.properties.is_empty() {
151 return TypeId::NEVER;
152 }
153 let key_types: Vec<TypeId> = shape
154 .properties
155 .iter()
156 .map(|p| self.interner().literal_string_atom(p.name))
157 .collect();
158 self.interner().union(key_types)
159 }
160 TypeData::ObjectWithIndex(shape_id) => {
161 let shape = self.interner().object_shape(shape_id);
162 let mut key_types: Vec<TypeId> = shape
163 .properties
164 .iter()
165 .map(|p| self.interner().literal_string_atom(p.name))
166 .collect();
167
168 if shape.string_index.is_some() {
169 key_types.push(TypeId::STRING);
170 key_types.push(TypeId::NUMBER);
171 } else if shape.number_index.is_some() {
172 key_types.push(TypeId::NUMBER);
173 }
174
175 if key_types.is_empty() {
176 TypeId::NEVER
177 } else {
178 self.interner().union(key_types)
179 }
180 }
181 TypeData::Array(_) => self.interner().union(self.array_keyof_keys()),
182 TypeData::Tuple(elements) => {
183 let elements = self.interner().tuple_list(elements);
184 let mut key_types: Vec<TypeId> = Vec::new();
185 self.append_tuple_indices(&elements, 0, &mut key_types);
186 let mut array_keys = self.array_keyof_keys();
187 key_types.append(&mut array_keys);
188 if key_types.is_empty() {
189 return TypeId::NEVER;
190 }
191 self.interner().union(key_types)
192 }
193 TypeData::Intrinsic(kind) => match kind {
194 IntrinsicKind::Any => {
195 self.interner()
197 .union3(TypeId::STRING, TypeId::NUMBER, TypeId::SYMBOL)
198 }
199 IntrinsicKind::Unknown => {
200 TypeId::NEVER
202 }
203 IntrinsicKind::Never
204 | IntrinsicKind::Void
205 | IntrinsicKind::Null
206 | IntrinsicKind::Undefined
207 | IntrinsicKind::Object
208 | IntrinsicKind::Function => TypeId::NEVER,
209 IntrinsicKind::String
210 | IntrinsicKind::Number
211 | IntrinsicKind::Boolean
212 | IntrinsicKind::Bigint
213 | IntrinsicKind::Symbol => self.apparent_primitive_keyof(kind),
214 },
215 TypeData::Literal(literal) => {
216 if let Some(kind) = self.apparent_literal_kind(&literal) {
217 self.apparent_primitive_keyof(kind)
218 } else {
219 self.interner().keyof(operand)
220 }
221 }
222 TypeData::TemplateLiteral(_) => {
223 self.apparent_primitive_keyof(IntrinsicKind::String)
224 }
225 TypeData::Intersection(members) => {
227 self.keyof_intersection(members, operand)
229 }
230 TypeData::Lazy(def_id) => {
232 match self.resolver().resolve_lazy(def_id, self.interner()) {
233 Some(resolved) => {
234 self.recurse_keyof(resolved)
236 }
237 None => {
238 self.interner().keyof(operand)
240 }
241 }
242 }
243 TypeData::Application(_app_id) => {
245 let evaluated = self.evaluate(evaluated_operand);
247 self.recurse_keyof(evaluated)
249 }
250 _ => self.interner().keyof(operand),
252 }
253 }
254 }
255
256 pub(crate) fn keyof_intersection(&mut self, members: TypeListId, _operand: TypeId) -> TypeId {
258 let members = self.interner().type_list(members);
259 let mut key_sets: Vec<TypeId> = Vec::with_capacity(members.len());
262 for &m in members.iter() {
263 key_sets.push(self.recurse_keyof(m));
264 }
265 self.interner().union(key_sets)
266 }
267
268 pub(crate) fn array_keyof_keys(&self) -> Vec<TypeId> {
270 let mut keys = Vec::new();
271 keys.push(TypeId::NUMBER);
272 keys.push(self.interner().literal_string("length"));
273 for &name in ARRAY_METHODS_RETURN_ANY {
274 keys.push(self.interner().literal_string(name));
275 }
276 for &name in ARRAY_METHODS_RETURN_BOOLEAN {
277 keys.push(self.interner().literal_string(name));
278 }
279 for &name in ARRAY_METHODS_RETURN_NUMBER {
280 keys.push(self.interner().literal_string(name));
281 }
282 for &name in ARRAY_METHODS_RETURN_VOID {
283 keys.push(self.interner().literal_string(name));
284 }
285 for &name in ARRAY_METHODS_RETURN_STRING {
286 keys.push(self.interner().literal_string(name));
287 }
288 keys
289 }
290
291 pub(crate) fn append_tuple_indices(
294 &self,
295 elements: &[TupleElement],
296 base: usize,
297 out: &mut Vec<TypeId>,
298 ) -> Option<usize> {
299 let mut index = base;
300
301 for element in elements {
302 if element.rest {
303 match self.interner().lookup(element.type_id) {
304 Some(TypeData::Tuple(rest_elements)) => {
305 let rest_elements = self.interner().tuple_list(rest_elements);
306 match self.append_tuple_indices(&rest_elements, index, out) {
307 Some(next) => {
308 index = next;
309 continue;
310 }
311 None => return None,
312 }
313 }
314 _ => return None,
315 }
316 }
317 out.push(self.interner().literal_string(&index.to_string()));
318 index += 1;
319 }
320
321 Some(index)
322 }
323
324 pub(crate) fn intersect_keyof_sets(&self, key_sets: &[TypeId]) -> Option<TypeId> {
327 let mut parsed_sets = Vec::with_capacity(key_sets.len());
328 for &key_set in key_sets {
329 let mut parsed = KeyofKeySet::new();
330 if !parsed.insert_type(self.interner(), key_set) {
331 return None;
332 }
333 parsed_sets.push(parsed);
334 }
335
336 let mut all_string = true;
337 let mut string_possible = true;
338 let mut common_literals: Option<FxHashSet<Atom>> = None;
339 let mut all_number = true;
340 let mut all_symbol = true;
341
342 for set in &parsed_sets {
343 if set.has_string {
344 } else {
346 all_string = false;
347 if set.string_literals.is_empty() {
348 string_possible = false;
349 } else {
350 common_literals = Some(match common_literals {
351 Some(mut existing) => {
352 existing.retain(|atom| set.string_literals.contains(atom));
353 existing
354 }
355 None => set.string_literals.clone(),
356 });
357 }
358 }
359
360 if !set.has_number {
361 all_number = false;
362 }
363 if !set.has_symbol {
364 all_symbol = false;
365 }
366 }
367
368 let mut result_keys = Vec::new();
369 if string_possible {
370 if all_string {
371 result_keys.push(TypeId::STRING);
372 } else if let Some(common) = common_literals {
373 for atom in common {
374 result_keys.push(self.interner().literal_string_atom(atom));
375 }
376 }
377 }
378 if all_number {
379 result_keys.push(TypeId::NUMBER);
380 }
381 if all_symbol {
382 result_keys.push(TypeId::SYMBOL);
383 }
384
385 if result_keys.is_empty() {
386 Some(TypeId::NEVER)
387 } else if result_keys.len() == 1 {
388 Some(result_keys[0])
389 } else {
390 Some(self.interner().union(result_keys))
391 }
392 }
393}