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