1use std::sync::Arc;
2
3use mago_word::Word;
4use mago_word::ascii_lowercase_word;
5use mago_word::word;
6
7use crate::metadata::CodebaseMetadata;
8use crate::reference::ReferenceSource;
9use crate::reference::SymbolReferences;
10use crate::symbol::SymbolKind;
11use crate::symbol::Symbols;
12use crate::ttype::TType;
13use crate::ttype::TypeRef;
14use crate::ttype::atomic::alias::TAlias;
15use crate::ttype::atomic::array::TArray;
16use crate::ttype::atomic::array::key::ArrayKey;
17use crate::ttype::atomic::callable::TCallable;
18use crate::ttype::atomic::conditional::TConditional;
19use crate::ttype::atomic::derived::TDerived;
20use crate::ttype::atomic::generic::TGenericParameter;
21use crate::ttype::atomic::iterable::TIterable;
22use crate::ttype::atomic::mixed::TMixed;
23use crate::ttype::atomic::object::TObject;
24use crate::ttype::atomic::object::r#enum::TEnum;
25use crate::ttype::atomic::object::named::TNamedObject;
26use crate::ttype::atomic::reference::TReference;
27use crate::ttype::atomic::reference::TReferenceMemberSelector;
28use crate::ttype::atomic::resource::TResource;
29use crate::ttype::atomic::scalar::TScalar;
30use crate::ttype::atomic::scalar::class_like_string::TClassLikeString;
31use crate::ttype::atomic::scalar::int::TInteger;
32use crate::ttype::atomic::scalar::string::TString;
33use crate::ttype::atomic::scalar::string::TStringLiteral;
34use crate::ttype::get_arraykey;
35use crate::ttype::get_mixed;
36use crate::ttype::union::TUnion;
37use crate::ttype::union::populate_union_type;
38
39pub mod alias;
40pub mod array;
41pub mod callable;
42pub mod conditional;
43pub mod derived;
44pub mod generic;
45pub mod iterable;
46pub mod mixed;
47pub mod object;
48pub mod reference;
49pub mod resource;
50pub mod scalar;
51
52#[allow(clippy::derived_hash_with_manual_eq)]
53#[derive(Debug, Clone, Eq, Hash, PartialOrd, Ord)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55pub enum TAtomic {
56 Scalar(TScalar),
57 Callable(TCallable),
58 Mixed(TMixed),
59 Object(TObject),
60 Array(TArray),
61 Iterable(TIterable),
62 Resource(TResource),
63 Reference(TReference),
64 GenericParameter(TGenericParameter),
65 Variable(Word),
66 Conditional(TConditional),
67 Derived(TDerived),
68 Alias(TAlias),
69 Never,
70 Null,
71 Void,
72 Placeholder,
73}
74
75impl PartialEq for TAtomic {
76 #[inline]
77 fn eq(&self, other: &Self) -> bool {
78 if std::ptr::eq(self, other) {
79 return true;
80 }
81
82 match (self, other) {
83 (TAtomic::Scalar(a), TAtomic::Scalar(b)) => a == b,
84 (TAtomic::Callable(a), TAtomic::Callable(b)) => a == b,
85 (TAtomic::Mixed(a), TAtomic::Mixed(b)) => a == b,
86 (TAtomic::Object(a), TAtomic::Object(b)) => a == b,
87 (TAtomic::Array(a), TAtomic::Array(b)) => a == b,
88 (TAtomic::Iterable(a), TAtomic::Iterable(b)) => a == b,
89 (TAtomic::Resource(a), TAtomic::Resource(b)) => a == b,
90 (TAtomic::Reference(a), TAtomic::Reference(b)) => a == b,
91 (TAtomic::GenericParameter(a), TAtomic::GenericParameter(b)) => a == b,
92 (TAtomic::Variable(a), TAtomic::Variable(b)) => a == b,
93 (TAtomic::Conditional(a), TAtomic::Conditional(b)) => a == b,
94 (TAtomic::Derived(a), TAtomic::Derived(b)) => a == b,
95 (TAtomic::Alias(a), TAtomic::Alias(b)) => a == b,
96 (TAtomic::Never, TAtomic::Never)
97 | (TAtomic::Null, TAtomic::Null)
98 | (TAtomic::Void, TAtomic::Void)
99 | (TAtomic::Placeholder, TAtomic::Placeholder) => true,
100 _ => false,
101 }
102 }
103}
104
105impl TAtomic {
106 #[must_use]
108 pub fn contains_placeholder(&self) -> bool {
109 match self {
110 TAtomic::Placeholder => true,
111 TAtomic::Object(TObject::Named(named)) => {
112 named.get_type_parameters().is_some_and(|params| params.iter().any(|p| p.contains_placeholder()))
113 }
114 TAtomic::Array(array) => array.contains_placeholder(),
115 _ => false,
116 }
117 }
118
119 #[must_use]
120 pub fn is_numeric(&self) -> bool {
121 match self {
122 TAtomic::Scalar(scalar) => scalar.is_numeric(),
123 TAtomic::GenericParameter(parameter) => parameter.constraint.is_numeric(),
124 _ => false,
125 }
126 }
127
128 #[must_use]
129 pub fn is_int_or_float(&self) -> bool {
130 match self {
131 TAtomic::Scalar(scalar) => scalar.is_int_or_float(),
132 TAtomic::GenericParameter(parameter) => parameter.constraint.is_int_or_float(),
133 _ => false,
134 }
135 }
136
137 #[must_use]
140 pub fn effective_int_or_float(&self) -> Option<bool> {
141 match self {
142 TAtomic::Scalar(TScalar::Integer(_)) => Some(true),
143 TAtomic::Scalar(TScalar::Float(_)) => Some(false),
144 TAtomic::GenericParameter(parameter) => parameter.constraint.effective_int_or_float(),
145 _ => None,
146 }
147 }
148
149 #[must_use]
150 pub const fn is_mixed(&self) -> bool {
151 matches!(self, TAtomic::Mixed(_))
152 }
153
154 #[must_use]
155 pub const fn is_vanilla_mixed(&self) -> bool {
156 matches!(self, TAtomic::Mixed(_))
157 }
158
159 #[must_use]
160 pub const fn is_mixed_isset_from_loop(&self) -> bool {
161 matches!(self, TAtomic::Mixed(mixed) if mixed.is_isset_from_loop())
162 }
163
164 #[must_use]
165 pub const fn is_never(&self) -> bool {
166 matches!(self, TAtomic::Never)
167 }
168
169 #[must_use]
170 pub fn is_templated_as_never(&self) -> bool {
171 matches!(self, TAtomic::GenericParameter(parameter) if parameter.constraint.is_never())
172 }
173
174 #[must_use]
175 pub fn is_templated_as_mixed(&self) -> bool {
176 matches!(self, TAtomic::GenericParameter(parameter) if parameter.is_constrained_as_mixed())
177 }
178
179 #[must_use]
180 pub fn is_templated_as_vanilla_mixed(&self) -> bool {
181 matches!(self, TAtomic::GenericParameter(parameter) if parameter.is_constrained_as_vanilla_mixed())
182 }
183
184 pub fn map_generic_parameter_constraint<F, T>(&self, f: F) -> Option<T>
185 where
186 F: FnOnce(&TUnion) -> T,
187 {
188 if let TAtomic::GenericParameter(parameter) = self { Some(f(parameter.constraint.as_ref())) } else { None }
189 }
190
191 #[must_use]
192 pub fn is_enum(&self) -> bool {
193 matches!(self, TAtomic::Object(TObject::Enum(TEnum { .. })))
194 }
195
196 #[must_use]
197 pub fn is_enum_case(&self) -> bool {
198 matches!(self, TAtomic::Object(TObject::Enum(TEnum { case: Some(_), .. })))
199 }
200
201 pub fn is_object_type(&self) -> bool {
202 match self {
203 TAtomic::Object(_) => true,
204 TAtomic::Callable(callable) => {
205 callable.get_signature().is_none_or(callable::TCallableSignature::is_closure)
206 }
207 TAtomic::GenericParameter(parameter) => parameter.is_constrained_as_objecty(),
208 _ => false,
209 }
210 }
211
212 #[must_use]
213 pub fn is_static(&self) -> bool {
214 matches!(self, TAtomic::Object(TObject::Named(named_object)) if named_object.is_static)
215 }
216
217 #[must_use]
218 pub fn is_this(&self) -> bool {
219 matches!(self, TAtomic::Object(TObject::Named(named_object)) if named_object.is_this())
220 }
221
222 #[must_use]
223 pub fn get_object_or_enum_name(&self) -> Option<Word> {
224 match self {
225 TAtomic::Object(object) => match object {
226 TObject::Named(named_object) => Some(named_object.get_name()),
227 TObject::Enum(r#enum) => Some(r#enum.get_name()),
228 _ => None,
229 },
230 _ => None,
231 }
232 }
233
234 #[must_use]
235 pub fn get_all_object_names(&self) -> Vec<Word> {
236 let mut object_names = vec![];
237
238 if let TAtomic::Object(object) = self {
239 match object {
240 TObject::Named(named_object) => object_names.push(named_object.get_name()),
241 TObject::Enum(r#enum) => object_names.push(r#enum.get_name()),
242 _ => {}
243 }
244 }
245
246 for intersection_type in self.get_intersection_types().unwrap_or_default() {
247 object_names.extend(intersection_type.get_all_object_names());
248 }
249
250 object_names
251 }
252
253 #[must_use]
254 pub fn is_stdclass(&self) -> bool {
255 matches!(&self, TAtomic::Object(object) if {
256 object.get_name().is_some_and(|name| name.as_bytes().eq_ignore_ascii_case(b"stdClass"))
257 })
258 }
259
260 #[must_use]
261 pub fn is_generator(&self) -> bool {
262 matches!(&self, TAtomic::Object(object) if {
263 object.get_name().is_some_and(|name| name.as_bytes().eq_ignore_ascii_case(b"Generator"))
264 })
265 }
266
267 #[must_use]
268 pub fn get_generator_parameters(&self) -> Option<(TUnion, TUnion, TUnion, TUnion)> {
269 let generator_parameters = 'parameters: {
270 let TAtomic::Object(TObject::Named(named_object)) = self else {
271 break 'parameters None;
272 };
273
274 let object_name = named_object.get_name();
275 if !object_name.as_bytes().eq_ignore_ascii_case(b"Generator") {
276 break 'parameters None;
277 }
278
279 let parameters = named_object.get_type_parameters().unwrap_or_default();
280 match parameters {
281 [] => Some((get_mixed(), get_mixed(), get_mixed(), get_mixed())),
282 [a] => Some((get_mixed(), a.clone(), get_mixed(), get_mixed())),
283 [a, b] => Some((a.clone(), b.clone(), get_mixed(), get_mixed())),
284 [a, b, c] => Some((a.clone(), b.clone(), c.clone(), get_mixed())),
285 [a, b, c, d] => Some((a.clone(), b.clone(), c.clone(), d.clone())),
286 _ => None,
287 }
288 };
289
290 if let Some(parameters) = generator_parameters {
291 return Some(parameters);
292 }
293
294 if let Some(intersection_types) = self.get_intersection_types() {
295 for intersection_type in intersection_types {
296 if let Some(parameters) = intersection_type.get_generator_parameters() {
297 return Some(parameters);
298 }
299 }
300 }
301
302 None
303 }
304
305 #[must_use]
306 pub fn is_templated_as_object(&self) -> bool {
307 matches!(self, TAtomic::GenericParameter(parameter) if {
308 parameter.constraint.is_objecty() && parameter.intersection_types.is_none()
309 })
310 }
311
312 #[inline]
313 #[must_use]
314 pub const fn is_list(&self) -> bool {
315 matches!(self, TAtomic::Array(array) if array.is_list())
316 }
317
318 #[inline]
319 #[must_use]
320 pub fn is_vanilla_array(&self) -> bool {
321 matches!(self, TAtomic::Array(array) if array.is_vanilla())
322 }
323
324 pub fn get_list_element_type(&self) -> Option<&TUnion> {
325 match self {
326 TAtomic::Array(array) => array.get_list().map(array::list::TList::get_element_type),
327 _ => None,
328 }
329 }
330
331 #[inline]
332 pub fn is_non_empty_list(&self) -> bool {
333 matches!(self, TAtomic::Array(array) if array.get_list().is_some_and(array::list::TList::is_non_empty))
334 }
335
336 #[inline]
337 #[must_use]
338 pub fn is_empty_array(&self) -> bool {
339 matches!(self, TAtomic::Array(array) if array.is_empty())
340 }
341
342 #[inline]
343 #[must_use]
344 pub const fn is_keyed_array(&self) -> bool {
345 matches!(self, TAtomic::Array(array) if array.is_keyed())
346 }
347
348 pub fn is_non_empty_keyed_array(&self) -> bool {
349 matches!(self, TAtomic::Array(array) if array.get_keyed().is_some_and(array::keyed::TKeyedArray::is_non_empty))
350 }
351
352 #[inline]
353 #[must_use]
354 pub const fn is_array(&self) -> bool {
355 matches!(self, TAtomic::Array(_))
356 }
357
358 #[inline]
359 #[must_use]
360 pub const fn is_iterable(&self) -> bool {
361 matches!(self, TAtomic::Iterable(_))
362 }
363
364 #[inline]
365 #[must_use]
366 pub fn extends_or_implements(&self, codebase: &CodebaseMetadata, interface: &[u8]) -> bool {
367 let object = match self {
368 TAtomic::Object(object) => object,
369 TAtomic::GenericParameter(parameter) => {
370 if let Some(intersection_types) = parameter.get_intersection_types() {
371 for intersection_type in intersection_types {
372 if intersection_type.extends_or_implements(codebase, interface) {
373 return true;
374 }
375 }
376 }
377
378 for constraint_atomic in parameter.constraint.types.as_ref() {
379 if constraint_atomic.extends_or_implements(codebase, interface) {
380 return true;
381 }
382 }
383
384 return false;
385 }
386 TAtomic::Iterable(iterable) => {
387 if let Some(intersection_types) = iterable.get_intersection_types() {
388 for intersection_type in intersection_types {
389 if intersection_type.extends_or_implements(codebase, interface) {
390 return true;
391 }
392 }
393 }
394
395 return false;
396 }
397 TAtomic::Never => return true,
399 _ => return false,
400 };
401
402 if let Some(object_name) = object.get_name() {
403 if object_name.as_bytes() == interface {
404 return true;
405 }
406
407 if codebase.is_instance_of(object_name.as_bytes(), interface) {
408 return true;
409 }
410 }
411
412 if let Some(intersection_types) = object.get_intersection_types() {
413 for intersection_type in intersection_types {
414 if intersection_type.extends_or_implements(codebase, interface) {
415 return true;
416 }
417 }
418 }
419
420 false
421 }
422
423 #[inline]
424 #[must_use]
425 pub fn is_countable(&self, codebase: &CodebaseMetadata) -> bool {
426 match self {
427 TAtomic::Array(_) => true,
428 _ => self.extends_or_implements(codebase, b"Countable"),
429 }
430 }
431
432 #[inline]
433 #[must_use]
434 pub fn could_be_countable(&self, codebase: &CodebaseMetadata) -> bool {
435 self.is_mixed() || self.is_countable(codebase)
436 }
437
438 #[inline]
439 #[must_use]
440 pub fn is_traversable(&self, codebase: &CodebaseMetadata) -> bool {
441 self.extends_or_implements(codebase, b"Traversable")
442 || self.extends_or_implements(codebase, b"Iterator")
443 || self.extends_or_implements(codebase, b"IteratorAggregate")
444 || self.extends_or_implements(codebase, b"Generator")
445 }
446
447 #[inline]
448 #[must_use]
449 pub fn is_array_or_traversable(&self, codebase: &CodebaseMetadata) -> bool {
450 match self {
451 TAtomic::Iterable(_) => true,
452 TAtomic::Array(_) => true,
453 _ => self.is_traversable(codebase),
454 }
455 }
456
457 #[inline]
458 #[must_use]
459 pub fn could_be_array_or_traversable(&self, codebase: &CodebaseMetadata) -> bool {
460 self.is_mixed() || self.is_array_or_traversable(codebase)
461 }
462
463 #[must_use]
464 pub fn is_non_empty_array(&self) -> bool {
465 matches!(self, TAtomic::Array(array) if array.is_non_empty())
466 }
467
468 pub fn to_array_key(&self) -> Option<ArrayKey> {
469 match self {
470 TAtomic::Scalar(TScalar::Integer(int)) => int.get_literal_value().map(ArrayKey::Integer),
471 TAtomic::Scalar(TScalar::String(TString { literal: Some(TStringLiteral::Value(value)), .. })) => {
472 Some(ArrayKey::String(*value))
473 }
474 TAtomic::Scalar(TScalar::ClassLikeString(TClassLikeString::Literal { value })) => {
475 Some(ArrayKey::String(*value))
476 }
477 _ => None,
478 }
479 }
480
481 #[must_use]
482 pub fn get_array_key_type(&self) -> Option<TUnion> {
483 match self {
484 TAtomic::Array(array) => array.get_key_type(),
485 _ => None,
486 }
487 }
488
489 #[must_use]
490 pub fn get_array_value_type(&self) -> Option<TUnion> {
491 match self {
492 TAtomic::Array(array) => array.get_value_type(),
493 _ => None,
494 }
495 }
496
497 #[inline]
498 #[must_use]
499 pub const fn is_generic_scalar(&self) -> bool {
500 matches!(self, TAtomic::Scalar(TScalar::Generic))
501 }
502
503 #[inline]
504 #[must_use]
505 pub const fn is_some_scalar(&self) -> bool {
506 matches!(self, TAtomic::Scalar(_))
507 }
508
509 #[inline]
510 #[must_use]
511 pub const fn is_boring_scalar(&self) -> bool {
512 matches!(
513 self,
514 TAtomic::Scalar(scalar) if scalar.is_boring()
515 )
516 }
517
518 #[inline]
519 #[must_use]
520 pub const fn is_any_string(&self) -> bool {
521 matches!(
522 self,
523 TAtomic::Scalar(scalar) if scalar.is_any_string()
524 )
525 }
526
527 #[inline]
528 #[must_use]
529 pub const fn is_string(&self) -> bool {
530 matches!(
531 self,
532 TAtomic::Scalar(scalar) if scalar.is_string()
533 )
534 }
535
536 #[inline]
537 #[must_use]
538 pub const fn is_string_of_literal_origin(&self) -> bool {
539 matches!(
540 self,
541 TAtomic::Scalar(scalar) if scalar.is_literal_origin_string()
542 )
543 }
544
545 #[inline]
546 #[must_use]
547 pub const fn is_non_empty_string(&self) -> bool {
548 matches!(
549 self,
550 TAtomic::Scalar(scalar) if scalar.is_non_empty_string()
551 )
552 }
553
554 #[inline]
555 #[must_use]
556 pub const fn is_known_literal_string(&self) -> bool {
557 matches!(
558 self,
559 TAtomic::Scalar(scalar) if scalar.is_known_literal_string()
560 )
561 }
562
563 #[inline]
564 #[must_use]
565 pub const fn is_literal_class_string(&self) -> bool {
566 matches!(
567 self,
568 TAtomic::Scalar(scalar) if scalar.is_literal_class_string()
569 )
570 }
571
572 #[must_use]
573 pub const fn is_string_subtype(&self) -> bool {
574 matches!(
575 self,
576 TAtomic::Scalar(scalar) if scalar.is_non_boring_string()
577 )
578 }
579
580 #[inline]
581 #[must_use]
582 pub const fn is_array_key(&self) -> bool {
583 matches!(
584 self,
585 TAtomic::Scalar(scalar) if scalar.is_array_key()
586 )
587 }
588
589 #[inline]
590 #[must_use]
591 pub const fn is_int(&self) -> bool {
592 matches!(
593 self,
594 TAtomic::Scalar(scalar) if scalar.is_int()
595 )
596 }
597
598 #[inline]
599 #[must_use]
600 pub const fn is_literal_int(&self) -> bool {
601 matches!(
602 self,
603 TAtomic::Scalar(scalar) if scalar.is_literal_int()
604 )
605 }
606
607 #[inline]
608 #[must_use]
609 pub const fn is_float(&self) -> bool {
610 matches!(
611 self,
612 TAtomic::Scalar(scalar) if scalar.is_float()
613 )
614 }
615
616 #[inline]
617 #[must_use]
618 pub const fn is_literal_float(&self) -> bool {
619 matches!(
620 self,
621 TAtomic::Scalar(scalar) if scalar.is_literal_float()
622 )
623 }
624
625 #[inline]
626 #[must_use]
627 pub const fn is_null(&self) -> bool {
628 matches!(self, TAtomic::Null)
629 }
630
631 #[inline]
632 #[must_use]
633 pub const fn is_void(&self) -> bool {
634 matches!(self, TAtomic::Void)
635 }
636
637 #[inline]
638 #[must_use]
639 pub const fn is_bool(&self) -> bool {
640 matches!(
641 self,
642 TAtomic::Scalar(scalar) if scalar.is_bool()
643 )
644 }
645
646 #[inline]
647 #[must_use]
648 pub const fn is_general_bool(&self) -> bool {
649 matches!(
650 self,
651 TAtomic::Scalar(scalar) if scalar.is_general_bool()
652 )
653 }
654
655 #[inline]
656 #[must_use]
657 pub const fn is_general_string(&self) -> bool {
658 matches!(
659 self,
660 TAtomic::Scalar(scalar) if scalar.is_general_string()
661 )
662 }
663
664 #[inline]
665 #[must_use]
666 pub const fn is_true(&self) -> bool {
667 matches!(
668 self,
669 TAtomic::Scalar(scalar) if scalar.is_true()
670 )
671 }
672
673 #[inline]
674 #[must_use]
675 pub const fn is_false(&self) -> bool {
676 matches!(
677 self,
678 TAtomic::Scalar(scalar) if scalar.is_false()
679 )
680 }
681
682 #[inline]
683 #[must_use]
684 pub const fn is_falsable(&self) -> bool {
685 matches!(
686 self,
687 TAtomic::Scalar(scalar) if scalar.is_false() || scalar.is_general_bool() || scalar.is_generic()
688 )
689 }
690
691 #[inline]
692 #[must_use]
693 pub const fn is_resource(&self) -> bool {
694 matches!(self, TAtomic::Resource(_))
695 }
696
697 #[inline]
698 #[must_use]
699 pub const fn is_closed_resource(&self) -> bool {
700 matches!(self, TAtomic::Resource(resource) if resource.is_closed())
701 }
702
703 #[inline]
704 #[must_use]
705 pub const fn is_open_resource(&self) -> bool {
706 matches!(self, TAtomic::Resource(resource) if resource.is_open())
707 }
708
709 #[inline]
710 #[must_use]
711 pub const fn is_literal(&self) -> bool {
712 match self {
713 TAtomic::Scalar(scalar) => scalar.is_literal_value(),
714 TAtomic::Null => true,
715 _ => false,
716 }
717 }
718
719 #[inline]
720 #[must_use]
721 pub const fn is_callable(&self) -> bool {
722 matches!(self, TAtomic::Callable(_))
723 }
724
725 #[inline]
726 #[must_use]
727 pub const fn is_conditional(&self) -> bool {
728 matches!(self, TAtomic::Conditional(_))
729 }
730
731 #[inline]
732 #[must_use]
733 pub const fn is_generic_parameter(&self) -> bool {
734 matches!(self, TAtomic::GenericParameter(_))
735 }
736
737 #[inline]
738 #[must_use]
739 pub const fn get_generic_parameter_name(&self) -> Option<Word> {
740 match self {
741 TAtomic::GenericParameter(parameter) => Some(parameter.parameter_name),
742 _ => None,
743 }
744 }
745
746 #[inline]
748 #[must_use]
749 pub const fn can_be_callable(&self) -> bool {
750 matches!(
751 self,
752 TAtomic::Callable(_)
753 | TAtomic::Scalar(TScalar::String(_))
754 | TAtomic::Array(TArray::List(_) | TArray::Keyed(_))
755 | TAtomic::Object(TObject::Named(_))
756 )
757 }
758
759 #[must_use]
760 pub fn is_truthy(&self) -> bool {
761 match &self {
762 TAtomic::Scalar(scalar) => scalar.is_truthy(),
763 TAtomic::Array(array) => array.is_truthy(),
764 TAtomic::Mixed(mixed) => mixed.is_truthy(),
765 TAtomic::Resource(resource) => resource.closed.is_none_or(|closed| !closed),
766 TAtomic::Object(_) | TAtomic::Callable(_) => true,
767 _ => false,
768 }
769 }
770
771 #[must_use]
772 pub fn is_falsy(&self) -> bool {
773 match &self {
774 TAtomic::Scalar(scalar) if scalar.is_falsy() => true,
775 TAtomic::Array(array) if array.is_falsy() => true,
776 TAtomic::Mixed(mixed) if mixed.is_falsy() => true,
777 TAtomic::Resource(resource) => resource.closed.is_some_and(|closed| closed),
778 TAtomic::Null | TAtomic::Void => true,
779 _ => false,
780 }
781 }
782
783 #[must_use]
784 pub fn is_array_accessible_with_string_key(&self) -> bool {
785 matches!(self, TAtomic::Array(array) if array.is_keyed())
786 }
787
788 #[must_use]
789 pub fn is_array_accessible_with_int_or_string_key(&self) -> bool {
790 matches!(self, TAtomic::Array(_))
791 }
792
793 #[must_use]
794 pub fn is_derived(&self) -> bool {
795 matches!(self, TAtomic::Derived(_))
796 }
797
798 #[must_use]
799 pub fn clone_without_intersection_types(&self) -> TAtomic {
800 let mut clone = self.clone();
801 match &mut clone {
802 TAtomic::Object(TObject::Named(named_object)) => {
803 named_object.intersection_types = None;
804 }
805 TAtomic::GenericParameter(parameter) => {
806 parameter.intersection_types = None;
807 }
808 TAtomic::Iterable(iterable) => {
809 iterable.intersection_types = None;
810 }
811 TAtomic::Reference(TReference::Symbol { intersection_types, .. }) => {
812 *intersection_types = None;
813 }
814 TAtomic::Derived(TDerived::Intersection(intersection)) => {
815 if let Some(intersection_types) = intersection.get_intersection_types_mut() {
816 intersection_types.clear();
817 }
818 }
819 _ => {}
820 }
821
822 clone
823 }
824
825 pub fn remove_placeholders(&mut self) {
826 match self {
827 TAtomic::Array(array) => {
828 array.remove_placeholders();
829 }
830 TAtomic::Object(TObject::Named(named_object)) => {
831 let name = named_object.get_name();
832 if let Some(type_parameters) = named_object.get_type_parameters_mut() {
833 if name.as_bytes().eq_ignore_ascii_case(b"Traversable") {
834 let has_kv_pair = type_parameters.len() == 2;
835
836 if let Some(key_or_value_param) = type_parameters.get_mut(0)
837 && matches!(key_or_value_param.get_single(), TAtomic::Placeholder)
838 {
839 *key_or_value_param = if has_kv_pair { get_arraykey() } else { get_mixed() };
840 }
841
842 if has_kv_pair
843 && let Some(value_param) = type_parameters.get_mut(1)
844 && matches!(value_param.get_single(), TAtomic::Placeholder)
845 {
846 *value_param = get_mixed();
847 }
848 } else {
849 for type_param in type_parameters {
850 if matches!(type_param.get_single(), TAtomic::Placeholder) {
851 *type_param = get_mixed();
852 }
853 }
854 }
855 }
856 }
857 _ => {}
858 }
859 }
860
861 #[must_use]
862 pub fn get_literal_string_value(&self) -> Option<&[u8]> {
863 match self {
864 TAtomic::Scalar(scalar) => scalar.get_known_literal_string_value(),
865 _ => None,
866 }
867 }
868
869 #[must_use]
870 pub fn get_class_string_value(&self) -> Option<Word> {
871 match self {
872 TAtomic::Scalar(scalar) => scalar.get_literal_class_string_value(),
873 _ => None,
874 }
875 }
876
877 #[must_use]
878 pub fn get_integer(&self) -> Option<TInteger> {
879 match self {
880 TAtomic::Scalar(TScalar::Integer(integer)) => Some(*integer),
881 _ => None,
882 }
883 }
884
885 #[must_use]
886 pub fn get_literal_int_value(&self) -> Option<i64> {
887 match self {
888 TAtomic::Scalar(scalar) => scalar.get_literal_int_value(),
889 _ => None,
890 }
891 }
892
893 #[must_use]
894 pub fn get_maximum_int_value(&self) -> Option<i64> {
895 match self {
896 TAtomic::Scalar(scalar) => scalar.get_maximum_int_value(),
897 _ => None,
898 }
899 }
900
901 #[must_use]
902 pub fn get_minimum_int_value(&self) -> Option<i64> {
903 match self {
904 TAtomic::Scalar(scalar) => scalar.get_minimum_int_value(),
905 _ => None,
906 }
907 }
908
909 #[must_use]
910 pub fn get_literal_float_value(&self) -> Option<f64> {
911 match self {
912 TAtomic::Scalar(scalar) => scalar.get_literal_float_value(),
913 _ => None,
914 }
915 }
916}
917
918impl TType for TAtomic {
919 fn get_child_nodes(&self) -> Vec<TypeRef<'_>> {
920 match self {
921 TAtomic::Array(ttype) => ttype.get_child_nodes(),
922 TAtomic::Callable(ttype) => ttype.get_child_nodes(),
923 TAtomic::Conditional(ttype) => ttype.get_child_nodes(),
924 TAtomic::Derived(ttype) => ttype.get_child_nodes(),
925 TAtomic::GenericParameter(ttype) => ttype.get_child_nodes(),
926 TAtomic::Iterable(ttype) => ttype.get_child_nodes(),
927 TAtomic::Mixed(ttype) => ttype.get_child_nodes(),
928 TAtomic::Object(ttype) => ttype.get_child_nodes(),
929 TAtomic::Reference(ttype) => ttype.get_child_nodes(),
930 TAtomic::Resource(ttype) => ttype.get_child_nodes(),
931 TAtomic::Scalar(ttype) => ttype.get_child_nodes(),
932 TAtomic::Alias(ttype) => ttype.get_child_nodes(),
933 _ => vec![],
934 }
935 }
936
937 fn can_be_intersected(&self) -> bool {
938 match self {
939 TAtomic::Object(ttype) => ttype.can_be_intersected(),
940 TAtomic::Reference(ttype) => ttype.can_be_intersected(),
941 TAtomic::GenericParameter(ttype) => ttype.can_be_intersected(),
942 TAtomic::Iterable(ttype) => ttype.can_be_intersected(),
943 TAtomic::Array(ttype) => ttype.can_be_intersected(),
944 TAtomic::Callable(ttype) => ttype.can_be_intersected(),
945 TAtomic::Mixed(ttype) => ttype.can_be_intersected(),
946 TAtomic::Scalar(ttype) => ttype.can_be_intersected(),
947 TAtomic::Resource(ttype) => ttype.can_be_intersected(),
948 TAtomic::Conditional(ttype) => ttype.can_be_intersected(),
949 TAtomic::Derived(ttype) => ttype.can_be_intersected(),
950 TAtomic::Alias(ttype) => ttype.can_be_intersected(),
951 _ => false,
952 }
953 }
954
955 fn get_intersection_types(&self) -> Option<&[TAtomic]> {
956 match self {
957 TAtomic::Object(ttype) => ttype.get_intersection_types(),
958 TAtomic::Reference(ttype) => ttype.get_intersection_types(),
959 TAtomic::GenericParameter(ttype) => ttype.get_intersection_types(),
960 TAtomic::Iterable(ttype) => ttype.get_intersection_types(),
961 TAtomic::Array(ttype) => ttype.get_intersection_types(),
962 TAtomic::Callable(ttype) => ttype.get_intersection_types(),
963 TAtomic::Mixed(ttype) => ttype.get_intersection_types(),
964 TAtomic::Scalar(ttype) => ttype.get_intersection_types(),
965 TAtomic::Resource(ttype) => ttype.get_intersection_types(),
966 TAtomic::Conditional(ttype) => ttype.get_intersection_types(),
967 TAtomic::Derived(ttype) => ttype.get_intersection_types(),
968 TAtomic::Alias(ttype) => ttype.get_intersection_types(),
969 _ => None,
970 }
971 }
972
973 fn get_intersection_types_mut(&mut self) -> Option<&mut Vec<TAtomic>> {
974 match self {
975 TAtomic::Object(ttype) => ttype.get_intersection_types_mut(),
976 TAtomic::Reference(ttype) => ttype.get_intersection_types_mut(),
977 TAtomic::GenericParameter(ttype) => ttype.get_intersection_types_mut(),
978 TAtomic::Iterable(ttype) => ttype.get_intersection_types_mut(),
979 TAtomic::Array(ttype) => ttype.get_intersection_types_mut(),
980 TAtomic::Callable(ttype) => ttype.get_intersection_types_mut(),
981 TAtomic::Mixed(ttype) => ttype.get_intersection_types_mut(),
982 TAtomic::Scalar(ttype) => ttype.get_intersection_types_mut(),
983 TAtomic::Resource(ttype) => ttype.get_intersection_types_mut(),
984 TAtomic::Conditional(ttype) => ttype.get_intersection_types_mut(),
985 TAtomic::Derived(ttype) => ttype.get_intersection_types_mut(),
986 TAtomic::Alias(ttype) => ttype.get_intersection_types_mut(),
987 _ => None,
988 }
989 }
990
991 fn has_intersection_types(&self) -> bool {
992 match self {
993 TAtomic::Object(ttype) => ttype.has_intersection_types(),
994 TAtomic::Reference(ttype) => ttype.has_intersection_types(),
995 TAtomic::GenericParameter(ttype) => ttype.has_intersection_types(),
996 TAtomic::Iterable(ttype) => ttype.has_intersection_types(),
997 TAtomic::Array(ttype) => ttype.has_intersection_types(),
998 TAtomic::Callable(ttype) => ttype.has_intersection_types(),
999 TAtomic::Mixed(ttype) => ttype.has_intersection_types(),
1000 TAtomic::Scalar(ttype) => ttype.has_intersection_types(),
1001 TAtomic::Resource(ttype) => ttype.has_intersection_types(),
1002 TAtomic::Conditional(ttype) => ttype.has_intersection_types(),
1003 TAtomic::Derived(ttype) => ttype.has_intersection_types(),
1004 TAtomic::Alias(ttype) => ttype.has_intersection_types(),
1005 _ => false,
1006 }
1007 }
1008
1009 fn add_intersection_type(&mut self, intersection_type: TAtomic) -> bool {
1010 match self {
1011 TAtomic::Object(ttype) => ttype.add_intersection_type(intersection_type),
1012 TAtomic::Reference(ttype) => ttype.add_intersection_type(intersection_type),
1013 TAtomic::GenericParameter(ttype) => ttype.add_intersection_type(intersection_type),
1014 TAtomic::Iterable(ttype) => ttype.add_intersection_type(intersection_type),
1015 TAtomic::Array(ttype) => ttype.add_intersection_type(intersection_type),
1016 TAtomic::Callable(ttype) => ttype.add_intersection_type(intersection_type),
1017 TAtomic::Mixed(ttype) => ttype.add_intersection_type(intersection_type),
1018 TAtomic::Scalar(ttype) => ttype.add_intersection_type(intersection_type),
1019 TAtomic::Resource(ttype) => ttype.add_intersection_type(intersection_type),
1020 TAtomic::Conditional(ttype) => ttype.add_intersection_type(intersection_type),
1021 TAtomic::Derived(ttype) => ttype.add_intersection_type(intersection_type),
1022 TAtomic::Alias(ttype) => ttype.add_intersection_type(intersection_type),
1023 _ => false,
1024 }
1025 }
1026
1027 fn needs_population(&self) -> bool {
1028 if let Some(intersection) = self.get_intersection_types() {
1029 for intersection_type in intersection {
1030 if intersection_type.needs_population() {
1031 return true;
1032 }
1033 }
1034 }
1035
1036 match self {
1037 TAtomic::Object(ttype) => ttype.needs_population(),
1038 TAtomic::Reference(ttype) => ttype.needs_population(),
1039 TAtomic::GenericParameter(ttype) => ttype.needs_population(),
1040 TAtomic::Iterable(ttype) => ttype.needs_population(),
1041 TAtomic::Array(ttype) => ttype.needs_population(),
1042 TAtomic::Callable(ttype) => ttype.needs_population(),
1043 TAtomic::Conditional(ttype) => ttype.needs_population(),
1044 TAtomic::Derived(ttype) => ttype.needs_population(),
1045 TAtomic::Scalar(ttype) => ttype.needs_population(),
1046 TAtomic::Mixed(ttype) => ttype.needs_population(),
1047 TAtomic::Resource(ttype) => ttype.needs_population(),
1048 TAtomic::Alias(ttype) => ttype.needs_population(),
1049 _ => false,
1050 }
1051 }
1052
1053 #[inline]
1054 fn is_expandable(&self) -> bool {
1055 if let Some(intersection) = self.get_intersection_types() {
1056 for intersection_type in intersection {
1057 if intersection_type.is_expandable() {
1058 return true;
1059 }
1060 }
1061 }
1062
1063 match self {
1064 TAtomic::Object(ttype) => ttype.is_expandable(),
1065 TAtomic::Reference(ttype) => ttype.is_expandable(),
1066 TAtomic::GenericParameter(ttype) => ttype.is_expandable(),
1067 TAtomic::Iterable(ttype) => ttype.is_expandable(),
1068 TAtomic::Array(ttype) => ttype.is_expandable(),
1069 TAtomic::Callable(ttype) => ttype.is_expandable(),
1070 TAtomic::Conditional(ttype) => ttype.is_expandable(),
1071 TAtomic::Derived(ttype) => ttype.is_expandable(),
1072 TAtomic::Scalar(ttype) => ttype.is_expandable(),
1073 TAtomic::Mixed(ttype) => ttype.is_expandable(),
1074 TAtomic::Resource(ttype) => ttype.is_expandable(),
1075 TAtomic::Alias(ttype) => ttype.is_expandable(),
1076 _ => false,
1077 }
1078 }
1079
1080 fn is_complex(&self) -> bool {
1081 if let Some(intersection) = self.get_intersection_types() {
1082 for intersection_type in intersection {
1083 if intersection_type.is_complex() {
1084 return true;
1085 }
1086 }
1087 }
1088
1089 match self {
1090 TAtomic::Object(ttype) => ttype.is_complex(),
1091 TAtomic::Reference(ttype) => ttype.is_complex(),
1092 TAtomic::GenericParameter(ttype) => ttype.is_complex(),
1093 TAtomic::Iterable(ttype) => ttype.is_complex(),
1094 TAtomic::Array(ttype) => ttype.is_complex(),
1095 TAtomic::Callable(ttype) => ttype.is_complex(),
1096 TAtomic::Conditional(ttype) => ttype.is_complex(),
1097 TAtomic::Derived(ttype) => ttype.is_complex(),
1098 TAtomic::Scalar(ttype) => ttype.is_complex(),
1099 TAtomic::Mixed(ttype) => ttype.is_complex(),
1100 TAtomic::Resource(ttype) => ttype.is_complex(),
1101 TAtomic::Alias(ttype) => ttype.is_complex(),
1102 _ => false,
1103 }
1104 }
1105
1106 fn get_id(&self) -> Word {
1107 match self {
1108 TAtomic::Scalar(scalar) => scalar.get_id(),
1109 TAtomic::Array(array) => array.get_id(),
1110 TAtomic::Callable(callable) => callable.get_id(),
1111 TAtomic::Object(object) => object.get_id(),
1112 TAtomic::Reference(reference) => reference.get_id(),
1113 TAtomic::Mixed(mixed) => mixed.get_id(),
1114 TAtomic::Resource(resource) => resource.get_id(),
1115 TAtomic::Iterable(iterable) => iterable.get_id(),
1116 TAtomic::GenericParameter(parameter) => parameter.get_id(),
1117 TAtomic::Conditional(conditional) => conditional.get_id(),
1118 TAtomic::Alias(alias) => alias.get_id(),
1119 TAtomic::Derived(derived) => derived.get_id(),
1120 TAtomic::Variable(name) => *name,
1121 TAtomic::Never => word("never"),
1122 TAtomic::Null => word("null"),
1123 TAtomic::Void => word("void"),
1124 TAtomic::Placeholder => word("_"),
1125 }
1126 }
1127
1128 fn get_pretty_id_with_indent(&self, indent: usize) -> Word {
1129 match self {
1130 TAtomic::Scalar(scalar) => scalar.get_pretty_id_with_indent(indent),
1131 TAtomic::Array(array) => array.get_pretty_id_with_indent(indent),
1132 TAtomic::Callable(callable) => callable.get_pretty_id_with_indent(indent),
1133 TAtomic::Object(object) => object.get_pretty_id_with_indent(indent),
1134 TAtomic::Reference(reference) => reference.get_pretty_id_with_indent(indent),
1135 TAtomic::Mixed(mixed) => mixed.get_pretty_id_with_indent(indent),
1136 TAtomic::Resource(resource) => resource.get_pretty_id_with_indent(indent),
1137 TAtomic::Iterable(iterable) => iterable.get_pretty_id_with_indent(indent),
1138 TAtomic::GenericParameter(parameter) => parameter.get_pretty_id_with_indent(indent),
1139 TAtomic::Conditional(conditional) => conditional.get_pretty_id_with_indent(indent),
1140 TAtomic::Alias(alias) => alias.get_pretty_id_with_indent(indent),
1141 TAtomic::Derived(derived) => derived.get_pretty_id_with_indent(indent),
1142 TAtomic::Variable(name) => *name,
1143 TAtomic::Never => word("never"),
1144 TAtomic::Null => word("null"),
1145 TAtomic::Void => word("void"),
1146 TAtomic::Placeholder => word("_"),
1147 }
1148 }
1149}
1150
1151pub fn populate_atomic_type(
1152 unpopulated_atomic: &mut TAtomic,
1153 codebase_symbols: &Symbols,
1154 reference_source: Option<&ReferenceSource>,
1155 symbol_references: &mut SymbolReferences,
1156 force: bool,
1157) {
1158 match unpopulated_atomic {
1159 TAtomic::Array(array) => match array {
1160 TArray::List(list) => {
1161 populate_union_type(
1162 Arc::make_mut(&mut list.element_type),
1163 codebase_symbols,
1164 reference_source,
1165 symbol_references,
1166 force,
1167 );
1168
1169 if let Some(known_elements) = list.known_elements.as_mut() {
1170 for (_, element_type) in known_elements.values_mut() {
1171 populate_union_type(element_type, codebase_symbols, reference_source, symbol_references, force);
1172 }
1173 }
1174 }
1175 TArray::Keyed(keyed_array) => {
1176 if let Some(known_items) = keyed_array.known_items.as_mut() {
1177 for (_, item_type) in known_items.values_mut() {
1178 populate_union_type(item_type, codebase_symbols, reference_source, symbol_references, force);
1179 }
1180 }
1181
1182 if let Some(parameters) = &mut keyed_array.parameters {
1183 populate_union_type(
1184 Arc::make_mut(&mut parameters.0),
1185 codebase_symbols,
1186 reference_source,
1187 symbol_references,
1188 force,
1189 );
1190
1191 populate_union_type(
1192 Arc::make_mut(&mut parameters.1),
1193 codebase_symbols,
1194 reference_source,
1195 symbol_references,
1196 force,
1197 );
1198 }
1199 }
1200 },
1201 TAtomic::Callable(TCallable::Signature(signature)) => {
1202 if let Some(return_type) = signature.get_return_type_mut() {
1203 populate_union_type(return_type, codebase_symbols, reference_source, symbol_references, force);
1204 }
1205
1206 for param in signature.get_parameters_mut() {
1207 if let Some(param_type) = param.get_type_signature_mut() {
1208 populate_union_type(param_type, codebase_symbols, reference_source, symbol_references, force);
1209 }
1210 }
1211
1212 for constraint in &mut signature.constraints {
1213 populate_union_type(
1214 Arc::make_mut(&mut constraint.input_type),
1215 codebase_symbols,
1216 reference_source,
1217 symbol_references,
1218 force,
1219 );
1220 populate_union_type(
1221 Arc::make_mut(&mut constraint.parameter_type),
1222 codebase_symbols,
1223 reference_source,
1224 symbol_references,
1225 force,
1226 );
1227 }
1228 }
1229 TAtomic::Object(TObject::Named(named_object)) => {
1230 let name = named_object.get_name();
1231
1232 if !named_object.is_intersection()
1233 && !named_object.has_type_parameters()
1234 && codebase_symbols.contains_enum(name)
1235 {
1236 *unpopulated_atomic = TAtomic::Object(TObject::new_enum(name));
1237 } else {
1238 if let Some(type_parameters) = named_object.get_type_parameters_mut() {
1239 for parameter in type_parameters {
1240 populate_union_type(parameter, codebase_symbols, reference_source, symbol_references, force);
1241 }
1242 }
1243
1244 if let Some(intersection_types) = named_object.get_intersection_types_mut() {
1245 for intersection_type in intersection_types {
1246 populate_atomic_type(
1247 intersection_type,
1248 codebase_symbols,
1249 reference_source,
1250 symbol_references,
1251 force,
1252 );
1253 }
1254 }
1255 }
1256
1257 if let Some(reference_source) = reference_source {
1258 match reference_source {
1259 ReferenceSource::Symbol(in_signature, a) => {
1260 symbol_references.add_symbol_reference_to_symbol(*a, name, *in_signature);
1261 }
1262 ReferenceSource::ClassLikeMember(in_signature, a, b) => {
1263 symbol_references.add_class_member_reference_to_symbol((*a, *b), name, *in_signature);
1264 }
1265 }
1266 }
1267 }
1268 TAtomic::Object(TObject::WithProperties(keyed_array)) => {
1269 for (_, item_type) in keyed_array.known_properties.values_mut() {
1270 populate_union_type(item_type, codebase_symbols, reference_source, symbol_references, force);
1271 }
1272 }
1273 TAtomic::Iterable(iterable) => {
1274 populate_union_type(
1275 iterable.get_key_type_mut(),
1276 codebase_symbols,
1277 reference_source,
1278 symbol_references,
1279 force,
1280 );
1281
1282 populate_union_type(
1283 iterable.get_value_type_mut(),
1284 codebase_symbols,
1285 reference_source,
1286 symbol_references,
1287 force,
1288 );
1289
1290 if let Some(intersection_types) = iterable.get_intersection_types_mut() {
1291 for intersection_type in intersection_types {
1292 populate_atomic_type(
1293 intersection_type,
1294 codebase_symbols,
1295 reference_source,
1296 symbol_references,
1297 force,
1298 );
1299 }
1300 }
1301 }
1302 TAtomic::Reference(reference) => match reference {
1303 TReference::Symbol { name, parameters, variances, intersection_types } => {
1304 if let Some(parameters) = parameters {
1305 for parameter in parameters {
1306 populate_union_type(parameter, codebase_symbols, reference_source, symbol_references, force);
1307 }
1308 }
1309
1310 if let Some(reference_source) = reference_source {
1311 match reference_source {
1312 ReferenceSource::Symbol(in_signature, a) => {
1313 symbol_references.add_symbol_reference_to_symbol(*a, *name, *in_signature);
1314 }
1315 ReferenceSource::ClassLikeMember(in_signature, a, b) => {
1316 symbol_references.add_class_member_reference_to_symbol((*a, *b), *name, *in_signature);
1317 }
1318 }
1319 }
1320
1321 if let Some(symbol_kind) = codebase_symbols.get_kind(ascii_lowercase_word(name.as_bytes())) {
1322 if symbol_kind == SymbolKind::Enum {
1323 *unpopulated_atomic = TAtomic::Object(TObject::new_enum(*name));
1324 } else {
1325 let intersection_types = intersection_types.take().map(|intersection_types| {
1326 intersection_types
1327 .into_iter()
1328 .map(|mut intersection_type| {
1329 populate_atomic_type(
1330 &mut intersection_type,
1331 codebase_symbols,
1332 reference_source,
1333 symbol_references,
1334 force,
1335 );
1336
1337 intersection_type
1338 })
1339 .collect::<Vec<_>>()
1340 });
1341
1342 let mut named_object = TNamedObject::new(*name)
1343 .with_type_parameters(parameters.clone())
1344 .with_variances(variances.clone());
1345 if let Some(intersection_types) = intersection_types {
1346 for intersection_type in intersection_types {
1347 named_object.add_intersection_type(intersection_type);
1348 }
1349 }
1350
1351 *unpopulated_atomic = TAtomic::Object(TObject::Named(named_object));
1352 }
1353 }
1354 }
1355 TReference::Member { class_like_name, member_selector } => {
1356 if let TReferenceMemberSelector::Identifier(member_name) = member_selector
1357 && let Some(reference_source) = reference_source
1358 {
1359 match reference_source {
1360 ReferenceSource::Symbol(in_signature, a) => symbol_references
1361 .add_symbol_reference_to_class_member(*a, (*class_like_name, *member_name), *in_signature),
1362 ReferenceSource::ClassLikeMember(in_signature, a, b) => symbol_references
1363 .add_class_member_reference_to_class_member(
1364 (*a, *b),
1365 (*class_like_name, *member_name),
1366 *in_signature,
1367 ),
1368 }
1369 }
1370 }
1371 TReference::Global { .. } => {
1372 }
1374 },
1375 TAtomic::GenericParameter(TGenericParameter { constraint, intersection_types, .. }) => {
1376 populate_union_type(
1377 Arc::make_mut(constraint),
1378 codebase_symbols,
1379 reference_source,
1380 symbol_references,
1381 force,
1382 );
1383
1384 if let Some(intersection_types) = intersection_types.as_mut() {
1385 for intersection_type in intersection_types {
1386 populate_atomic_type(
1387 intersection_type,
1388 codebase_symbols,
1389 reference_source,
1390 symbol_references,
1391 force,
1392 );
1393 }
1394 }
1395 }
1396 TAtomic::Scalar(TScalar::ClassLikeString(
1397 TClassLikeString::OfType { constraint, .. } | TClassLikeString::Generic { constraint, .. },
1398 )) => {
1399 populate_atomic_type(
1400 Arc::make_mut(constraint),
1401 codebase_symbols,
1402 reference_source,
1403 symbol_references,
1404 force,
1405 );
1406 }
1407 TAtomic::Conditional(conditional) => {
1408 populate_union_type(
1409 conditional.get_subject_mut(),
1410 codebase_symbols,
1411 reference_source,
1412 symbol_references,
1413 force,
1414 );
1415
1416 populate_union_type(
1417 conditional.get_target_mut(),
1418 codebase_symbols,
1419 reference_source,
1420 symbol_references,
1421 force,
1422 );
1423
1424 populate_union_type(
1425 conditional.get_then_mut(),
1426 codebase_symbols,
1427 reference_source,
1428 symbol_references,
1429 force,
1430 );
1431
1432 populate_union_type(
1433 conditional.get_otherwise_mut(),
1434 codebase_symbols,
1435 reference_source,
1436 symbol_references,
1437 force,
1438 );
1439 }
1440 TAtomic::Derived(derived) => match derived {
1441 TDerived::IntMask(int_mask) => {
1442 for value in int_mask.get_values_mut() {
1443 populate_union_type(value, codebase_symbols, reference_source, symbol_references, force);
1444 }
1445 }
1446 TDerived::IndexAccess(index_access) => {
1447 populate_union_type(
1448 index_access.get_target_type_mut(),
1449 codebase_symbols,
1450 reference_source,
1451 symbol_references,
1452 force,
1453 );
1454
1455 populate_union_type(
1456 index_access.get_index_type_mut(),
1457 codebase_symbols,
1458 reference_source,
1459 symbol_references,
1460 force,
1461 );
1462 }
1463 TDerived::TemplateType(template_type) => {
1464 populate_union_type(
1465 template_type.get_object_mut(),
1466 codebase_symbols,
1467 reference_source,
1468 symbol_references,
1469 force,
1470 );
1471
1472 populate_union_type(
1473 template_type.get_class_name_mut(),
1474 codebase_symbols,
1475 reference_source,
1476 symbol_references,
1477 force,
1478 );
1479
1480 populate_union_type(
1481 template_type.get_template_name_mut(),
1482 codebase_symbols,
1483 reference_source,
1484 symbol_references,
1485 force,
1486 );
1487 }
1488 TDerived::Intersection(intersection) => {
1489 populate_union_type(
1490 intersection.get_base_type_mut(),
1491 codebase_symbols,
1492 reference_source,
1493 symbol_references,
1494 force,
1495 );
1496 if let Some(intersection_types) = intersection.get_intersection_types_mut() {
1497 for intersection_type in intersection_types {
1498 populate_atomic_type(
1499 intersection_type,
1500 codebase_symbols,
1501 reference_source,
1502 symbol_references,
1503 force,
1504 );
1505 }
1506 }
1507 }
1508 _ => {
1509 if let Some(target) = derived.get_target_type_mut() {
1510 populate_union_type(target, codebase_symbols, reference_source, symbol_references, force);
1511 }
1512 }
1513 },
1514 _ => {}
1515 }
1516}