tsz_solver/evaluate_rules/
keyof.rs1use crate::TypeDatabase;
6use crate::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::ReadonlyType(inner) => self.recurse_keyof(inner),
120 TypeData::TypeQuery(sym) => {
121 let resolved = self.resolver().resolve_symbol_ref(sym, self.interner());
123 if let Some(resolved) = resolved {
124 self.recurse_keyof(resolved)
125 } else {
126 TypeId::ERROR
127 }
128 }
129 TypeData::TypeParameter(param) | TypeData::Infer(param) => {
130 if let Some(constraint) = param.constraint {
131 if constraint == evaluated_operand {
132 self.interner().keyof(operand)
133 } else {
134 self.recurse_keyof(constraint)
135 }
136 } else {
137 self.interner().keyof(operand)
138 }
139 }
140 TypeData::Object(shape_id) => {
141 let shape = self.interner().object_shape(shape_id);
142 if shape.properties.is_empty() {
143 return TypeId::NEVER;
144 }
145 let key_types: Vec<TypeId> = shape
146 .properties
147 .iter()
148 .map(|p| self.interner().literal_string_atom(p.name))
149 .collect();
150 self.interner().union(key_types)
151 }
152 TypeData::ObjectWithIndex(shape_id) => {
153 let shape = self.interner().object_shape(shape_id);
154 let mut key_types: Vec<TypeId> = shape
155 .properties
156 .iter()
157 .map(|p| self.interner().literal_string_atom(p.name))
158 .collect();
159
160 if shape.string_index.is_some() {
161 key_types.push(TypeId::STRING);
162 key_types.push(TypeId::NUMBER);
163 } else if shape.number_index.is_some() {
164 key_types.push(TypeId::NUMBER);
165 }
166
167 if key_types.is_empty() {
168 TypeId::NEVER
169 } else {
170 self.interner().union(key_types)
171 }
172 }
173 TypeData::Array(_) => self.interner().union(self.array_keyof_keys()),
174 TypeData::Tuple(elements) => {
175 let elements = self.interner().tuple_list(elements);
176 let mut key_types: Vec<TypeId> = Vec::new();
177 self.append_tuple_indices(&elements, 0, &mut key_types);
178 let mut array_keys = self.array_keyof_keys();
179 key_types.append(&mut array_keys);
180 if key_types.is_empty() {
181 return TypeId::NEVER;
182 }
183 self.interner().union(key_types)
184 }
185 TypeData::Intrinsic(kind) => match kind {
186 IntrinsicKind::Any => {
187 self.interner()
189 .union3(TypeId::STRING, TypeId::NUMBER, TypeId::SYMBOL)
190 }
191 IntrinsicKind::Unknown => {
192 TypeId::NEVER
194 }
195 IntrinsicKind::Never
196 | IntrinsicKind::Void
197 | IntrinsicKind::Null
198 | IntrinsicKind::Undefined
199 | IntrinsicKind::Object
200 | IntrinsicKind::Function => TypeId::NEVER,
201 IntrinsicKind::String
202 | IntrinsicKind::Number
203 | IntrinsicKind::Boolean
204 | IntrinsicKind::Bigint
205 | IntrinsicKind::Symbol => self.apparent_primitive_keyof(kind),
206 },
207 TypeData::Literal(literal) => {
208 if let Some(kind) = self.apparent_literal_kind(&literal) {
209 self.apparent_primitive_keyof(kind)
210 } else {
211 self.interner().keyof(operand)
212 }
213 }
214 TypeData::TemplateLiteral(_) => {
215 self.apparent_primitive_keyof(IntrinsicKind::String)
216 }
217 TypeData::Intersection(members) => {
219 self.keyof_intersection(members, operand)
221 }
222 TypeData::Lazy(def_id) => {
224 match self.resolver().resolve_lazy(def_id, self.interner()) {
225 Some(resolved) => {
226 self.recurse_keyof(resolved)
228 }
229 None => {
230 self.interner().keyof(operand)
232 }
233 }
234 }
235 TypeData::Application(_app_id) => {
237 let evaluated = self.evaluate(evaluated_operand);
239 self.recurse_keyof(evaluated)
241 }
242 _ => self.interner().keyof(operand),
244 }
245 }
246 }
247
248 pub(crate) fn keyof_intersection(&mut self, members: TypeListId, _operand: TypeId) -> TypeId {
250 let members = self.interner().type_list(members);
251 let mut key_sets: Vec<TypeId> = Vec::with_capacity(members.len());
254 for &m in members.iter() {
255 key_sets.push(self.recurse_keyof(m));
256 }
257 self.interner().union(key_sets)
258 }
259
260 pub(crate) fn array_keyof_keys(&self) -> Vec<TypeId> {
262 let mut keys = Vec::new();
263 keys.push(TypeId::NUMBER);
264 keys.push(self.interner().literal_string("length"));
265 for &name in ARRAY_METHODS_RETURN_ANY {
266 keys.push(self.interner().literal_string(name));
267 }
268 for &name in ARRAY_METHODS_RETURN_BOOLEAN {
269 keys.push(self.interner().literal_string(name));
270 }
271 for &name in ARRAY_METHODS_RETURN_NUMBER {
272 keys.push(self.interner().literal_string(name));
273 }
274 for &name in ARRAY_METHODS_RETURN_VOID {
275 keys.push(self.interner().literal_string(name));
276 }
277 for &name in ARRAY_METHODS_RETURN_STRING {
278 keys.push(self.interner().literal_string(name));
279 }
280 keys
281 }
282
283 pub(crate) fn append_tuple_indices(
286 &self,
287 elements: &[TupleElement],
288 base: usize,
289 out: &mut Vec<TypeId>,
290 ) -> Option<usize> {
291 let mut index = base;
292
293 for element in elements {
294 if element.rest {
295 match self.interner().lookup(element.type_id) {
296 Some(TypeData::Tuple(rest_elements)) => {
297 let rest_elements = self.interner().tuple_list(rest_elements);
298 match self.append_tuple_indices(&rest_elements, index, out) {
299 Some(next) => {
300 index = next;
301 continue;
302 }
303 None => return None,
304 }
305 }
306 _ => return None,
307 }
308 }
309 out.push(self.interner().literal_string(&index.to_string()));
310 index += 1;
311 }
312
313 Some(index)
314 }
315
316 pub(crate) fn intersect_keyof_sets(&self, key_sets: &[TypeId]) -> Option<TypeId> {
319 let mut parsed_sets = Vec::with_capacity(key_sets.len());
320 for &key_set in key_sets {
321 let mut parsed = KeyofKeySet::new();
322 if !parsed.insert_type(self.interner(), key_set) {
323 return None;
324 }
325 parsed_sets.push(parsed);
326 }
327
328 let mut all_string = true;
329 let mut string_possible = true;
330 let mut common_literals: Option<FxHashSet<Atom>> = None;
331 let mut all_number = true;
332 let mut all_symbol = true;
333
334 for set in &parsed_sets {
335 if set.has_string {
336 } else {
338 all_string = false;
339 if set.string_literals.is_empty() {
340 string_possible = false;
341 } else {
342 common_literals = Some(match common_literals {
343 Some(mut existing) => {
344 existing.retain(|atom| set.string_literals.contains(atom));
345 existing
346 }
347 None => set.string_literals.clone(),
348 });
349 }
350 }
351
352 if !set.has_number {
353 all_number = false;
354 }
355 if !set.has_symbol {
356 all_symbol = false;
357 }
358 }
359
360 let mut result_keys = Vec::new();
361 if string_possible {
362 if all_string {
363 result_keys.push(TypeId::STRING);
364 } else if let Some(common) = common_literals {
365 for atom in common {
366 result_keys.push(self.interner().literal_string_atom(atom));
367 }
368 }
369 }
370 if all_number {
371 result_keys.push(TypeId::NUMBER);
372 }
373 if all_symbol {
374 result_keys.push(TypeId::SYMBOL);
375 }
376
377 if result_keys.is_empty() {
378 Some(TypeId::NEVER)
379 } else if result_keys.len() == 1 {
380 Some(result_keys[0])
381 } else {
382 Some(self.interner().union(result_keys))
383 }
384 }
385}