1use ordered_float::OrderedFloat;
2use serde::Deserialize;
3use serde::Serialize;
4
5use mago_interner::StringIdentifier;
6use mago_interner::ThreadedInterner;
7use mago_span::Span;
8use mago_trinary::Trinary;
9
10use crate::function_like::FunctionLikeReflection;
11use crate::identifier::ClassLikeName;
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
16pub struct Template {
17 name: StringIdentifier,
19
20 constraints: Vec<TypeKind>,
22}
23
24#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
26pub enum ScalarTypeKind {
27 Bool,
29
30 Integer { min: Option<isize>, max: Option<isize> },
33
34 Float,
36
37 String,
39
40 IntegerMask(Vec<isize>),
43
44 IntegerMaskOf(StringIdentifier, StringIdentifier),
47
48 ClassString(Option<StringIdentifier>),
51
52 TraitString,
54
55 EnumString,
57
58 CallableString,
60
61 NumericString,
63
64 LiteralString,
66
67 LiteralInt,
69
70 NonEmptyString,
72
73 ArrayKey,
75
76 Numeric,
78
79 Scalar,
81}
82
83#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
85pub struct ObjectProperty {
86 pub name: StringIdentifier,
88
89 pub kind: TypeKind,
91
92 pub optional: bool,
94}
95
96#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
98pub enum ObjectTypeKind {
99 AnyObject,
101
102 TypedObject {
105 properties: Vec<ObjectProperty>,
107 },
108
109 NamedObject {
112 name: StringIdentifier,
114
115 type_parameters: Vec<TypeKind>,
117 },
118
119 AnonymousObject {
121 span: Span,
123 },
124
125 EnumCase {
127 enum_name: StringIdentifier,
129
130 case_name: StringIdentifier,
132 },
133
134 Generator { key: Box<TypeKind>, value: Box<TypeKind>, send: Box<TypeKind>, r#return: Box<TypeKind> },
137
138 Static {
140 scope: StringIdentifier,
142 },
143
144 Parent {
146 scope: StringIdentifier,
148 },
149
150 Self_ {
152 scope: StringIdentifier,
154 },
155}
156
157#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
159pub enum ArrayShapePropertyKey {
160 String(StringIdentifier),
161 Integer(isize),
162}
163
164#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
166pub struct ArrayShapeProperty {
167 pub key: Option<ArrayShapePropertyKey>,
169
170 pub kind: TypeKind,
172
173 pub optional: bool,
175}
176
177#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
179pub struct ArrayShape {
180 pub properties: Vec<ArrayShapeProperty>,
182
183 pub additional_properties: Option<(
186 Box<TypeKind>, Box<TypeKind>, )>,
189}
190
191#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
193pub enum ArrayTypeKind {
194 Array {
197 non_empty: bool,
199
200 key: Box<TypeKind>,
202
203 value: Box<TypeKind>,
205
206 known_size: Option<usize>,
208 },
209
210 List {
213 non_empty: bool,
215
216 value: Box<TypeKind>,
218
219 known_size: Option<usize>,
221 },
222
223 CallableArray,
225
226 Shape(ArrayShape),
229}
230
231#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
233pub struct CallableParameter {
234 pub kind: TypeKind,
236
237 pub optional: bool,
239
240 pub variadic: bool,
242}
243
244#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
246pub enum CallableTypeKind {
247 Callable { pure: bool, templates: Vec<Template>, parameters: Vec<CallableParameter>, return_kind: Box<TypeKind> },
250
251 Closure { pure: bool, templates: Vec<Template>, parameters: Vec<CallableParameter>, return_kind: Box<TypeKind> },
254}
255
256#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
258pub enum ValueTypeKind {
259 String {
262 value: StringIdentifier,
263 length: usize,
264 is_uppercase: Trinary,
265 is_lowercase: Trinary,
266 is_ascii_lowercase: Trinary,
267 is_ascii_uppercase: Trinary,
268 },
269
270 Integer { value: i64 },
273
274 Float { value: OrderedFloat<f64> },
277
278 Null,
280
281 True,
283
284 False,
286
287 ClassLikeConstant { class_like: ClassLikeName, constant: StringIdentifier },
290}
291
292#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
294pub struct ClassStringMapType {
295 key: Template,
297
298 value: Box<TypeKind>,
300}
301
302#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
304pub enum TypeKind {
305 Union { kinds: Vec<TypeKind> },
308
309 Intersection { kinds: Vec<TypeKind> },
312
313 Scalar(ScalarTypeKind),
315
316 Object(ObjectTypeKind),
318
319 Array(ArrayTypeKind),
321
322 Callable(CallableTypeKind),
324
325 Value(ValueTypeKind),
327
328 Conditional {
331 parameter: Box<TypeKind>,
333
334 condition: Box<TypeKind>,
336
337 then: Box<TypeKind>,
339
340 otherwise: Box<TypeKind>,
342 },
343
344 KeyOf { kind: Box<TypeKind> },
347
348 ValueOf { kind: Box<TypeKind> },
351
352 PropertiesOf { kind: Box<TypeKind> },
355
356 ClassStringMap {
359 key: Template,
361
362 value_kind: Box<TypeKind>,
364 },
365
366 Index { base_kind: Box<TypeKind>, index_kind: Box<TypeKind> },
369
370 Variable { name: StringIdentifier },
373
374 Iterable { key: Box<TypeKind>, value: Box<TypeKind> },
377
378 Void,
380
381 Resource,
383
384 ClosedResource,
386
387 Mixed {
389 explicit: bool,
391 },
392
393 Never,
395
396 GenericParameter { name: StringIdentifier, of: Box<TypeKind>, defined_in: StringIdentifier },
398}
399
400impl Template {
401 pub fn get_key(&self, interner: &ThreadedInterner) -> String {
402 let mut key = String::from(interner.lookup(&self.name));
403
404 for constraint in &self.constraints {
405 key.push_str(" of ");
406 key.push_str(&constraint.get_key(interner));
407 }
408
409 key
410 }
411}
412
413impl ArrayShapePropertyKey {
414 pub fn get_key(&self, interner: &ThreadedInterner) -> String {
415 match &self {
416 ArrayShapePropertyKey::String(string_identifier) => interner.lookup(string_identifier).to_owned(),
417 ArrayShapePropertyKey::Integer(i) => i.to_string(),
418 }
419 }
420}
421
422impl TypeKind {
423 #[inline]
424 pub fn is_nullable(&self) -> Trinary {
425 match &self {
426 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_nullable()).collect(),
427 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_nullable()).collect(),
428 TypeKind::Value(ValueTypeKind::Null) => Trinary::True,
429 TypeKind::Mixed { .. } => Trinary::Maybe,
430 TypeKind::Scalar(_) => Trinary::False,
431 TypeKind::Object(_) => todo!(),
432 TypeKind::Array(_) => todo!(),
433 TypeKind::Callable(_) => todo!(),
434 TypeKind::Conditional { then, otherwise, .. } => then.is_nullable() & otherwise.is_nullable(),
435 TypeKind::KeyOf { .. } => Trinary::False,
436 TypeKind::ValueOf { .. } => Trinary::Maybe,
437 TypeKind::PropertiesOf { .. } => Trinary::Maybe,
438 TypeKind::ClassStringMap { .. } => Trinary::False,
439 TypeKind::Index { .. } => Trinary::Maybe,
440 TypeKind::Variable { .. } => Trinary::Maybe,
441 TypeKind::Iterable { .. } => Trinary::False,
442 TypeKind::Void => Trinary::True,
443 TypeKind::Resource => Trinary::False,
444 TypeKind::ClosedResource => Trinary::False,
445 TypeKind::Never => Trinary::False,
446 TypeKind::GenericParameter { of, .. } => of.is_nullable(),
447 TypeKind::Value(_) => Trinary::False,
448 }
449 }
450
451 #[inline]
452 pub fn is_object(&self) -> bool {
453 match &self {
454 TypeKind::Union { kinds } => kinds.iter().all(|k| k.is_object()),
455 TypeKind::Intersection { kinds } => kinds.iter().any(|k| k.is_object()),
456 TypeKind::Conditional { then, otherwise, .. } => then.is_object() && otherwise.is_object(),
457 TypeKind::Callable(CallableTypeKind::Closure { .. }) => true,
458 TypeKind::GenericParameter { of, .. } => of.is_object(),
459 TypeKind::Object(_) => true,
460 _ => false,
461 }
462 }
463
464 #[inline]
465 pub fn is_resource(&self) -> bool {
466 match &self {
467 TypeKind::Union { kinds } => kinds.iter().all(|k| k.is_resource()),
468 TypeKind::Intersection { kinds } => kinds.iter().any(|k| k.is_resource()),
469 TypeKind::Conditional { then, otherwise, .. } => then.is_resource() && otherwise.is_resource(),
470 TypeKind::Resource | TypeKind::ClosedResource => true,
471 _ => false,
472 }
473 }
474
475 #[inline]
476 pub fn is_array(&self) -> bool {
477 match &self {
478 TypeKind::Union { kinds } => kinds.iter().all(|k| k.is_array()),
479 TypeKind::Intersection { kinds } => kinds.iter().any(|k| k.is_array()),
480 TypeKind::Conditional { then, otherwise, .. } => then.is_array() && otherwise.is_array(),
481 TypeKind::Array(_) => true,
482 _ => false,
483 }
484 }
485
486 #[inline]
487 pub fn is_bool(&self) -> Trinary {
488 match &self {
489 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_bool()).collect(),
490 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_bool()).collect(),
491 TypeKind::Conditional { then, otherwise, .. } => then.is_bool().and(otherwise.is_bool()),
492 TypeKind::Value(ValueTypeKind::True)
493 | TypeKind::Value(ValueTypeKind::False)
494 | TypeKind::Scalar(ScalarTypeKind::Bool) => Trinary::True,
495 TypeKind::Value(ValueTypeKind::ClassLikeConstant { .. }) => Trinary::Maybe,
496 TypeKind::GenericParameter { of, .. } => of.is_bool(),
497 _ => Trinary::False,
498 }
499 }
500
501 #[inline]
502 pub fn is_truthy(&self) -> Trinary {
503 match &self {
504 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_truthy()).collect(),
505 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_truthy()).collect(),
506 TypeKind::Conditional { then, otherwise, .. } => then.is_truthy().and(otherwise.is_truthy()),
507 TypeKind::Array(array_kind) => match array_kind {
508 ArrayTypeKind::Array { non_empty, known_size, .. }
509 if *non_empty || known_size.map(|s| s > 0).unwrap_or(false) =>
510 {
511 Trinary::True
512 }
513 ArrayTypeKind::List { non_empty, known_size, .. }
514 if *non_empty || known_size.map(|s| s > 0).unwrap_or(false) =>
515 {
516 Trinary::True
517 }
518 ArrayTypeKind::CallableArray => Trinary::True,
519 ArrayTypeKind::Shape(array_shape) => Trinary::from(!array_shape.properties.is_empty()),
520 _ => Trinary::Maybe,
521 },
522 TypeKind::Scalar(scalar_type_kind) => match scalar_type_kind {
523 ScalarTypeKind::Bool => Trinary::Maybe,
524 ScalarTypeKind::Integer { min, max } => {
525 if min.map(|m| m > 0).unwrap_or(false) {
526 Trinary::True
527 } else if max.map(|m| m < 0).unwrap_or(false) {
528 Trinary::False
529 } else {
530 Trinary::Maybe
531 }
532 }
533 ScalarTypeKind::Float => Trinary::Maybe,
534 ScalarTypeKind::String => Trinary::Maybe,
535 ScalarTypeKind::IntegerMask(bits) => {
536 if bits.iter().all(|b| *b > 0) {
537 Trinary::True
538 } else if bits.iter().all(|b| *b < 0) {
539 Trinary::False
540 } else {
541 Trinary::Maybe
542 }
543 }
544 ScalarTypeKind::IntegerMaskOf(_, _) => Trinary::Maybe,
545 ScalarTypeKind::ClassString(_)
546 | ScalarTypeKind::TraitString
547 | ScalarTypeKind::EnumString
548 | ScalarTypeKind::CallableString => Trinary::True,
549 ScalarTypeKind::NumericString => Trinary::Maybe, ScalarTypeKind::LiteralString => Trinary::Maybe,
551 ScalarTypeKind::LiteralInt => Trinary::Maybe,
552 ScalarTypeKind::NonEmptyString => Trinary::Maybe, ScalarTypeKind::ArrayKey => Trinary::Maybe,
554 ScalarTypeKind::Numeric => Trinary::Maybe,
555 ScalarTypeKind::Scalar => Trinary::Maybe,
556 },
557 TypeKind::Object(_) => Trinary::True,
558 TypeKind::Callable(_) => Trinary::True,
559 TypeKind::Value(value_type_kind) => match &value_type_kind {
560 ValueTypeKind::String { .. } => Trinary::Maybe,
561 ValueTypeKind::Integer { value } => {
562 if *value > 0 {
563 Trinary::True
564 } else {
565 Trinary::False
566 }
567 }
568 ValueTypeKind::Float { value } => {
569 if *value > OrderedFloat(0.0) {
570 Trinary::True
571 } else {
572 Trinary::False
573 }
574 }
575 ValueTypeKind::Null => Trinary::False,
576 ValueTypeKind::True => Trinary::True,
577 ValueTypeKind::False => Trinary::False,
578 ValueTypeKind::ClassLikeConstant { .. } => Trinary::Maybe,
579 },
580 TypeKind::Variable { .. } => Trinary::Maybe,
581 TypeKind::Iterable { .. } => Trinary::Maybe,
582 TypeKind::Void => Trinary::False,
583 TypeKind::Resource => Trinary::True,
584 TypeKind::ClosedResource => Trinary::True,
585 TypeKind::Never => Trinary::False,
586 TypeKind::GenericParameter { of, .. } => of.is_truthy(),
587 _ => Trinary::Maybe,
588 }
589 }
590
591 #[inline]
592 pub fn is_falsy(&self) -> Trinary {
593 self.is_truthy().negate()
594 }
595
596 #[inline]
597 pub fn is_float(&self) -> Trinary {
598 match &self {
599 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_float()).collect(),
600 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_float()).collect(),
601 TypeKind::Conditional { then, otherwise, .. } => then.is_float().and(otherwise.is_float()),
602 TypeKind::Scalar(scalar_type_kind) => match scalar_type_kind {
603 ScalarTypeKind::Float => Trinary::True,
604 ScalarTypeKind::Integer { .. } => Trinary::False,
605 ScalarTypeKind::IntegerMask(_) => Trinary::False,
606 ScalarTypeKind::IntegerMaskOf(_, _) => Trinary::False,
607 ScalarTypeKind::Numeric => Trinary::Maybe,
608 _ => Trinary::False,
609 },
610 TypeKind::Value(ValueTypeKind::Float { .. }) => Trinary::True,
611 TypeKind::Value(ValueTypeKind::ClassLikeConstant { .. }) => Trinary::Maybe,
612 _ => Trinary::False,
613 }
614 }
615
616 #[inline]
617 pub fn is_integer(&self) -> Trinary {
618 match &self {
619 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_integer()).collect(),
620 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_integer()).collect(),
621 TypeKind::Conditional { then, otherwise, .. } => then.is_integer().and(otherwise.is_integer()),
622 TypeKind::Scalar(scalar_type_kind) => match scalar_type_kind {
623 ScalarTypeKind::Integer { .. } => Trinary::True,
624 ScalarTypeKind::IntegerMask(_) => Trinary::True,
625 ScalarTypeKind::IntegerMaskOf(_, _) => Trinary::True,
626 ScalarTypeKind::LiteralInt => Trinary::True,
627 ScalarTypeKind::Numeric => Trinary::Maybe,
628 ScalarTypeKind::ArrayKey => Trinary::Maybe,
629 _ => Trinary::False,
630 },
631 TypeKind::Value(ValueTypeKind::Integer { .. }) => Trinary::True,
632 TypeKind::Value(ValueTypeKind::ClassLikeConstant { .. }) => Trinary::Maybe,
633 _ => Trinary::False,
634 }
635 }
636
637 #[inline]
638 pub fn is_string(&self) -> Trinary {
639 match &self {
640 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_string()).collect(),
641 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_string()).collect(),
642 TypeKind::Conditional { then, otherwise, .. } => then.is_string().and(otherwise.is_string()),
643 TypeKind::Scalar(scalar_type_kind) => match scalar_type_kind {
644 ScalarTypeKind::String => Trinary::True,
645 ScalarTypeKind::ClassString(_) => Trinary::True,
646 ScalarTypeKind::TraitString => Trinary::True,
647 ScalarTypeKind::EnumString => Trinary::True,
648 ScalarTypeKind::CallableString => Trinary::True,
649 ScalarTypeKind::NumericString => Trinary::True,
650 ScalarTypeKind::LiteralString => Trinary::True,
651 ScalarTypeKind::NonEmptyString => Trinary::True,
652 _ => Trinary::False,
653 },
654 TypeKind::Value(ValueTypeKind::String { .. }) => Trinary::True,
655 TypeKind::Value(ValueTypeKind::ClassLikeConstant { .. }) => Trinary::Maybe,
656 _ => Trinary::False,
657 }
658 }
659
660 #[inline]
661 pub fn is_non_empty_string(&self) -> Trinary {
662 match &self {
663 TypeKind::Union { kinds } => kinds.iter().map(|k| k.is_non_empty_string()).collect(),
664 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.is_non_empty_string()).collect(),
665 TypeKind::Conditional { then, otherwise, .. } => {
666 then.is_non_empty_string().and(otherwise.is_non_empty_string())
667 }
668 TypeKind::Scalar(scalar_type_kind) => match scalar_type_kind {
669 ScalarTypeKind::String => Trinary::Maybe,
670 ScalarTypeKind::ClassString(_) => Trinary::True,
671 ScalarTypeKind::TraitString => Trinary::True,
672 ScalarTypeKind::EnumString => Trinary::True,
673 ScalarTypeKind::CallableString => Trinary::True,
674 ScalarTypeKind::NumericString => Trinary::True,
675 ScalarTypeKind::LiteralString => Trinary::Maybe,
676 ScalarTypeKind::NonEmptyString => Trinary::True,
677 _ => Trinary::False,
678 },
679 TypeKind::Value(ValueTypeKind::String { length, .. }) => (*length > 0).into(),
680 TypeKind::Value(ValueTypeKind::ClassLikeConstant { .. }) => Trinary::Maybe,
681 _ => Trinary::False,
682 }
683 }
684
685 #[inline]
686 pub fn is_value(&self) -> bool {
687 matches!(self, TypeKind::Value(_))
688 }
689
690 #[inline]
691 pub fn is_templated_as_object(&self) -> bool {
692 matches!(self, TypeKind::GenericParameter { of, .. } if of.is_object())
693 }
694
695 #[inline]
696 pub fn is_generator(&self) -> bool {
697 matches!(self, TypeKind::Object(ObjectTypeKind::Generator { .. }))
698 }
699
700 pub fn get_key(&self, interner: &ThreadedInterner) -> String {
701 match &self {
702 TypeKind::Union { kinds } => kinds.iter().map(|k| k.get_key(interner)).collect::<Vec<_>>().join("|"),
703 TypeKind::Intersection { kinds } => kinds.iter().map(|k| k.get_key(interner)).collect::<Vec<_>>().join("&"),
704 TypeKind::Scalar(scalar_type_kind) => match &scalar_type_kind {
705 ScalarTypeKind::Bool => "bool".to_string(),
706 ScalarTypeKind::Float => "float".to_string(),
707 ScalarTypeKind::String => "string".to_string(),
708 ScalarTypeKind::Integer { min, max } => match (min, max) {
709 (None, None) => "int".to_string(),
710 (Some(min), None) => format!("int<{}, max>", min),
711 (None, Some(max)) => format!("int<min, {}>", max),
712 (Some(min), Some(max)) => format!("int<{}, {}>", min, max),
713 },
714 ScalarTypeKind::IntegerMask(vec) => {
715 let vec = vec.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ");
716
717 format!("int-mask<{}>", vec)
718 }
719 ScalarTypeKind::IntegerMaskOf(string_identifier, string_identifier1) => {
720 format!(
721 "int-mask-of<{}, {}>",
722 interner.lookup(string_identifier),
723 interner.lookup(string_identifier1)
724 )
725 }
726 ScalarTypeKind::ClassString(string_identifier) => {
727 if let Some(string_identifier) = string_identifier {
728 format!("class-string<{}>", interner.lookup(string_identifier))
729 } else {
730 "class-string".to_string()
731 }
732 }
733 ScalarTypeKind::TraitString => "trait-string".to_string(),
734 ScalarTypeKind::EnumString => "enum-string".to_string(),
735 ScalarTypeKind::CallableString => "callable-string".to_string(),
736 ScalarTypeKind::NumericString => "numeric-string".to_string(),
737 ScalarTypeKind::LiteralString => "literal-string".to_string(),
738 ScalarTypeKind::LiteralInt => "literal-int".to_string(),
739 ScalarTypeKind::NonEmptyString => "non-empty-string".to_string(),
740 ScalarTypeKind::ArrayKey => "array-key".to_string(),
741 ScalarTypeKind::Numeric => "numeric".to_string(),
742 ScalarTypeKind::Scalar => "scalar".to_string(),
743 },
744 TypeKind::Object(object_type_kind) => match &object_type_kind {
745 ObjectTypeKind::AnyObject => "object".to_string(),
746 ObjectTypeKind::TypedObject { properties } => {
747 let properties = properties
748 .iter()
749 .map(|property| {
750 let name = interner.lookup(&property.name);
751 let kind = property.kind.get_key(interner);
752
753 if property.optional {
754 format!("{}?: {}", name, kind)
755 } else {
756 format!("{}: {}", name, kind)
757 }
758 })
759 .collect::<Vec<_>>()
760 .join(", ");
761
762 format!("object{{{}}}", properties)
763 }
764 ObjectTypeKind::NamedObject { name, type_parameters } => {
765 let name = interner.lookup(name);
766
767 if type_parameters.is_empty() {
768 name.to_string()
769 } else {
770 let type_parameters = type_parameters
771 .iter()
772 .map(|type_parameter| type_parameter.get_key(interner))
773 .collect::<Vec<_>>()
774 .join(", ");
775
776 format!("{}<{}>", name, type_parameters)
777 }
778 }
779 ObjectTypeKind::AnonymousObject { span } => {
780 format!(
781 "anonymous-class@{}:{}-{}",
782 interner.lookup(&span.start.source.0),
783 span.start.offset,
784 span.end.offset
785 )
786 }
787 ObjectTypeKind::Generator { key, value, send, r#return } => {
788 let key = key.get_key(interner);
789 let value = value.get_key(interner);
790 let send = send.get_key(interner);
791 let r#return = r#return.get_key(interner);
792
793 format!("Generator<{}, {}, {}, {}>", key, value, send, r#return)
794 }
795 ObjectTypeKind::Static { .. } => "static".to_string(),
796 ObjectTypeKind::Parent { .. } => "parent".to_string(),
797 ObjectTypeKind::Self_ { .. } => "self".to_string(),
798 ObjectTypeKind::EnumCase { enum_name: name, case_name: case } => {
799 let name = interner.lookup(name);
800 let case = interner.lookup(case);
801
802 format!("enum({}::{})", name, case)
803 }
804 },
805 TypeKind::Array(array_type_kind) => match &array_type_kind {
806 ArrayTypeKind::Array { non_empty, key, value, .. } => {
807 let key = key.get_key(interner);
808 let value = value.get_key(interner);
809
810 if *non_empty {
811 format!("non-empty-array<{}, {}>", key, value)
812 } else {
813 format!("array<{}, {}>", key, value)
814 }
815 }
816 ArrayTypeKind::List { non_empty, value, .. } => {
817 let value = value.get_key(interner);
818
819 if *non_empty {
820 format!("non-empty-list<{}>", value)
821 } else {
822 format!("list<{}>", value)
823 }
824 }
825 ArrayTypeKind::CallableArray => "callable-array".to_string(),
826 ArrayTypeKind::Shape(array_shape) => {
827 let mut properties = array_shape
828 .properties
829 .iter()
830 .map(|property| {
831 let kind = property.kind.get_key(interner);
832
833 if let Some(key) = property.key.as_ref() {
834 let key = key.get_key(interner);
835
836 if property.optional {
837 format!("{}?: {}", key, kind)
838 } else {
839 format!("{}: {}", key, kind)
840 }
841 } else {
842 kind
843 }
844 })
845 .collect::<Vec<_>>()
846 .join(", ");
847
848 if let Some((key, value)) = &array_shape.additional_properties {
849 if matches!(
850 (key.as_ref(), value.as_ref()),
851 (TypeKind::Scalar(ScalarTypeKind::ArrayKey), TypeKind::Mixed { .. })
852 ) {
853 properties.push_str(", ...");
854 } else {
855 let key = key.get_key(interner);
856 let value = value.get_key(interner);
857
858 properties.push_str(&format!(", ...array<{}: {}>", key, value));
859 }
860 }
861
862 format!("array{{{}}}", properties)
863 }
864 },
865 TypeKind::Callable(callable_type_kind) => match &callable_type_kind {
866 CallableTypeKind::Callable { pure, templates, parameters, return_kind } => {
867 let parameters = parameters
868 .iter()
869 .map(|parameter| {
870 let mut kind = parameter.kind.get_key(interner);
871 if parameter.optional {
872 kind.push('=');
873 }
874
875 if parameter.variadic {
876 kind.push_str("...");
877 }
878
879 kind
880 })
881 .collect::<Vec<_>>()
882 .join(", ");
883
884 let return_kind = return_kind.get_key(interner);
885
886 let templates =
887 templates.iter().map(|template| template.get_key(interner)).collect::<Vec<_>>().join(", ");
888 let templates = if !templates.is_empty() { format!("<{}>", templates) } else { "".to_string() };
889
890 if *pure {
891 format!("(pure-callable{}({}): {})", templates, parameters, return_kind)
892 } else {
893 format!("(callable{}({}): {})", templates, parameters, return_kind)
894 }
895 }
896 CallableTypeKind::Closure { pure, templates, parameters, return_kind } => {
897 let parameters = parameters
898 .iter()
899 .map(|parameter| {
900 let mut kind = parameter.kind.get_key(interner);
901 if parameter.optional {
902 kind.push('=');
903 }
904
905 if parameter.variadic {
906 kind.push_str("...");
907 }
908
909 kind
910 })
911 .collect::<Vec<_>>()
912 .join(", ");
913
914 let return_kind = return_kind.get_key(interner);
915
916 let templates =
917 templates.iter().map(|template| template.get_key(interner)).collect::<Vec<_>>().join(", ");
918 let templates = if !templates.is_empty() { format!("<{}>", templates) } else { "".to_string() };
919
920 if *pure {
921 format!("(pure-Closure{}({}): {})", templates, parameters, return_kind)
922 } else {
923 format!("(Closure{}({}): {})", templates, parameters, return_kind)
924 }
925 }
926 },
927 TypeKind::Value(value_type_kind) => match &value_type_kind {
928 ValueTypeKind::String { value, .. } => {
929 format!("\"{}\"", value)
930 }
931 ValueTypeKind::Integer { value } => value.to_string(),
932 ValueTypeKind::Float { value } => value.to_string(),
933 ValueTypeKind::Null => "null".to_string(),
934 ValueTypeKind::True => "true".to_string(),
935 ValueTypeKind::False => "false".to_string(),
936 ValueTypeKind::ClassLikeConstant { class_like, constant } => {
937 format!("{}::{}", class_like.get_key(interner), interner.lookup(constant))
938 }
939 },
940 TypeKind::Conditional { parameter, condition, then, otherwise } => {
941 let parameter = parameter.get_key(interner);
942 let condition = condition.get_key(interner);
943 let then = then.get_key(interner);
944 let otherwise = otherwise.get_key(interner);
945
946 format!("{} is {} ? {} : {}", parameter, condition, then, otherwise)
947 }
948 TypeKind::KeyOf { kind } => {
949 let kind = kind.get_key(interner);
950
951 format!("key-of<{}>", kind)
952 }
953 TypeKind::ValueOf { kind } => {
954 let kind = kind.get_key(interner);
955
956 format!("value-of<{}>", kind)
957 }
958 TypeKind::PropertiesOf { kind } => {
959 let kind = kind.get_key(interner);
960
961 format!("properties-of<{}>", kind)
962 }
963 TypeKind::ClassStringMap { key, value_kind } => {
964 let mut template = interner.lookup(&key.name).to_owned();
965 for constraint in &key.constraints {
966 template.push_str(&format!(" of {}", constraint.get_key(interner)));
967 }
968
969 let value_kind = value_kind.get_key(interner);
970
971 format!("class-string-map<{}, {}>", template, value_kind)
972 }
973 TypeKind::Index { base_kind, index_kind } => {
974 let base_kind = base_kind.get_key(interner);
975 let index_kind = index_kind.get_key(interner);
976
977 format!("{}[{}]", base_kind, index_kind)
978 }
979 TypeKind::Variable { name } => interner.lookup(name).to_owned(),
980 TypeKind::Iterable { key, value } => {
981 let key = key.get_key(interner);
982 let value = value.get_key(interner);
983
984 format!("iterable<{}, {}>", key, value)
985 }
986 TypeKind::Void => "void".to_string(),
987 TypeKind::Resource => "resource".to_string(),
988 TypeKind::ClosedResource => "closed-resource".to_string(),
989 TypeKind::Mixed { explicit } => {
990 if *explicit {
991 "mixed".to_string()
992 } else {
993 "unknown".to_string()
994 }
995 }
996 TypeKind::Never => "never".to_string(),
997 TypeKind::GenericParameter { name, defined_in, .. } => {
998 format!("{}:{}", interner.lookup(name), interner.lookup(defined_in))
999 }
1000 }
1001 }
1002}
1003
1004pub fn bool_kind() -> TypeKind {
1006 TypeKind::Scalar(ScalarTypeKind::Bool)
1007}
1008
1009pub fn integer_kind() -> TypeKind {
1011 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: None })
1012}
1013
1014pub fn positive_integer_kind() -> TypeKind {
1015 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(1), max: None })
1016}
1017
1018pub fn non_negative_integer_kind() -> TypeKind {
1019 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(0), max: None })
1020}
1021
1022pub fn negative_integer_kind() -> TypeKind {
1023 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(-1) })
1024}
1025
1026pub fn non_positive_integer_kind() -> TypeKind {
1027 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(0) })
1028}
1029
1030pub fn minimum_integer_kind(min: isize) -> TypeKind {
1031 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(min), max: None })
1032}
1033
1034pub fn maximum_integer_kind(max: isize) -> TypeKind {
1035 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(max) })
1036}
1037
1038pub fn integer_range_kind(min: isize, max: isize) -> TypeKind {
1039 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(min), max: Some(max) })
1040}
1041
1042pub fn float_kind() -> TypeKind {
1044 TypeKind::Scalar(ScalarTypeKind::Float)
1045}
1046
1047pub fn string_kind() -> TypeKind {
1049 TypeKind::Scalar(ScalarTypeKind::String)
1050}
1051
1052pub fn non_empty_string_kind() -> TypeKind {
1054 TypeKind::Scalar(ScalarTypeKind::NonEmptyString)
1055}
1056
1057pub fn list_kind(value: TypeKind, known_size: Option<usize>) -> TypeKind {
1059 TypeKind::Array(ArrayTypeKind::List { non_empty: false, value: Box::new(value), known_size })
1060}
1061
1062pub fn array_kind(key: TypeKind, value: TypeKind, known_size: Option<usize>) -> TypeKind {
1064 TypeKind::Array(ArrayTypeKind::Array { non_empty: false, key: Box::new(key), value: Box::new(value), known_size })
1065}
1066
1067pub fn non_empty_list_kind(value: TypeKind, known_size: Option<usize>) -> TypeKind {
1069 TypeKind::Array(ArrayTypeKind::List { non_empty: true, value: Box::new(value), known_size })
1070}
1071
1072pub fn non_empty_array_kind(key: TypeKind, value: TypeKind, known_size: Option<usize>) -> TypeKind {
1074 TypeKind::Array(ArrayTypeKind::Array { non_empty: true, key: Box::new(key), value: Box::new(value), known_size })
1075}
1076
1077pub fn indexed_shape_property(kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1078 ArrayShapeProperty { key: None, kind, optional }
1079}
1080
1081pub fn string_shape_property(key: StringIdentifier, kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1082 ArrayShapeProperty { key: Some(ArrayShapePropertyKey::String(key)), kind, optional }
1083}
1084
1085pub fn integer_shape_property(key: isize, kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1086 ArrayShapeProperty { key: Some(ArrayShapePropertyKey::Integer(key)), kind, optional }
1087}
1088
1089pub fn array_shape_kind(
1090 properties: Vec<ArrayShapeProperty>,
1091 additional_properties: Option<(TypeKind, TypeKind)>,
1092) -> TypeKind {
1093 TypeKind::Array(ArrayTypeKind::Shape(ArrayShape {
1094 properties,
1095 additional_properties: additional_properties.map(|(k, v)| (Box::new(k), Box::new(v))),
1096 }))
1097}
1098
1099pub fn mixed_kind(explicit: bool) -> TypeKind {
1101 TypeKind::Mixed { explicit }
1102}
1103
1104pub fn union_kind(kinds: Vec<TypeKind>) -> TypeKind {
1106 TypeKind::Union { kinds }
1107}
1108
1109pub fn intersection_kind(kinds: Vec<TypeKind>) -> TypeKind {
1111 TypeKind::Intersection { kinds }
1112}
1113
1114pub fn callable_parameter(kind: TypeKind, optional: bool, variadic: bool) -> CallableParameter {
1116 CallableParameter { kind, optional, variadic }
1117}
1118
1119pub fn any_callable_kind() -> TypeKind {
1122 callable_kind(false, vec![], vec![callable_parameter(mixed_kind(false), true, true)], mixed_kind(false))
1123}
1124
1125pub fn callable_kind(
1127 pure: bool,
1128 templates: Vec<Template>,
1129 parameters: Vec<CallableParameter>,
1130 return_kind: TypeKind,
1131) -> TypeKind {
1132 TypeKind::Callable(CallableTypeKind::Callable { pure, templates, parameters, return_kind: Box::new(return_kind) })
1133}
1134
1135pub fn any_closure_kind() -> TypeKind {
1138 closure_kind(false, vec![], vec![callable_parameter(mixed_kind(false), true, true)], mixed_kind(false))
1139}
1140
1141pub fn closure_kind(
1143 pure: bool,
1144 templates: Vec<Template>,
1145 parameters: Vec<CallableParameter>,
1146 return_kind: TypeKind,
1147) -> TypeKind {
1148 TypeKind::Callable(CallableTypeKind::Closure { pure, templates, parameters, return_kind: Box::new(return_kind) })
1149}
1150
1151pub fn variable_kind(name: StringIdentifier) -> TypeKind {
1153 TypeKind::Variable { name }
1154}
1155
1156pub fn value_string_kind(
1158 value: StringIdentifier,
1159 length: usize,
1160 is_uppercase: Trinary,
1161 is_ascii_uppercase: Trinary,
1162 is_lowercase: Trinary,
1163 is_ascii_lowercase: Trinary,
1164) -> TypeKind {
1165 TypeKind::Value(ValueTypeKind::String {
1166 value,
1167 length,
1168 is_uppercase,
1169 is_lowercase,
1170 is_ascii_uppercase,
1171 is_ascii_lowercase,
1172 })
1173}
1174
1175pub fn value_integer_kind(value: i64) -> TypeKind {
1177 TypeKind::Value(ValueTypeKind::Integer { value })
1178}
1179
1180pub fn value_float_kind(value: OrderedFloat<f64>) -> TypeKind {
1182 TypeKind::Value(ValueTypeKind::Float { value })
1183}
1184
1185pub fn null_kind() -> TypeKind {
1187 TypeKind::Value(ValueTypeKind::Null)
1188}
1189
1190pub fn true_kind() -> TypeKind {
1192 TypeKind::Value(ValueTypeKind::True)
1193}
1194
1195pub fn false_kind() -> TypeKind {
1197 TypeKind::Value(ValueTypeKind::False)
1198}
1199
1200pub fn iterable_kind(key_kind: TypeKind, value_kind: TypeKind) -> TypeKind {
1202 TypeKind::Iterable { key: Box::new(key_kind), value: Box::new(value_kind) }
1203}
1204
1205pub fn any_object_kind() -> TypeKind {
1207 TypeKind::Object(ObjectTypeKind::AnyObject)
1208}
1209
1210pub fn static_kind(scope: StringIdentifier) -> TypeKind {
1212 TypeKind::Object(ObjectTypeKind::Static { scope })
1213}
1214
1215pub fn parent_kind(scope: StringIdentifier) -> TypeKind {
1217 TypeKind::Object(ObjectTypeKind::Parent { scope })
1218}
1219
1220pub fn self_kind(scope: StringIdentifier) -> TypeKind {
1222 TypeKind::Object(ObjectTypeKind::Self_ { scope })
1223}
1224
1225pub fn named_object_kind(name: StringIdentifier, type_parameters: Vec<TypeKind>) -> TypeKind {
1227 TypeKind::Object(ObjectTypeKind::NamedObject { name, type_parameters })
1228}
1229
1230pub fn anonymous_object_kind(span: Span) -> TypeKind {
1232 TypeKind::Object(ObjectTypeKind::AnonymousObject { span })
1233}
1234
1235pub fn enum_case_kind(enum_name: StringIdentifier, case_name: StringIdentifier) -> TypeKind {
1236 TypeKind::Object(ObjectTypeKind::EnumCase { enum_name, case_name })
1237}
1238
1239pub fn void_kind() -> TypeKind {
1241 TypeKind::Void
1242}
1243
1244pub fn never_kind() -> TypeKind {
1246 TypeKind::Never
1247}
1248
1249pub fn resource_kind() -> TypeKind {
1251 TypeKind::Resource
1252}
1253
1254pub fn closed_resource_kind() -> TypeKind {
1256 TypeKind::ClosedResource
1257}
1258
1259pub fn key_of_kind(kind: TypeKind) -> TypeKind {
1261 TypeKind::KeyOf { kind: Box::new(kind) }
1262}
1263
1264pub fn value_of_kind(kind: TypeKind) -> TypeKind {
1266 TypeKind::ValueOf { kind: Box::new(kind) }
1267}
1268
1269pub fn properties_of_kind(kind: TypeKind) -> TypeKind {
1271 TypeKind::PropertiesOf { kind: Box::new(kind) }
1272}
1273
1274pub fn conditional_kind(parameter: TypeKind, condition: TypeKind, then: TypeKind, otherwise: TypeKind) -> TypeKind {
1276 TypeKind::Conditional {
1277 parameter: Box::new(parameter),
1278 condition: Box::new(condition),
1279 then: Box::new(then),
1280 otherwise: Box::new(otherwise),
1281 }
1282}
1283
1284pub fn class_string_map_kind(key_template: Template, value_kind: TypeKind) -> TypeKind {
1286 TypeKind::ClassStringMap { key: key_template, value_kind: Box::new(value_kind) }
1287}
1288
1289pub fn index_kind(base_kind: TypeKind, index_kind: TypeKind) -> TypeKind {
1291 TypeKind::Index { base_kind: Box::new(base_kind), index_kind: Box::new(index_kind) }
1292}
1293
1294pub fn array_key_kind() -> TypeKind {
1296 TypeKind::Scalar(ScalarTypeKind::ArrayKey)
1297}
1298
1299impl From<&FunctionLikeReflection> for TypeKind {
1300 fn from(reflection: &FunctionLikeReflection) -> Self {
1301 let parameters: Vec<_> = reflection
1302 .parameters
1303 .iter()
1304 .map(|parameter| CallableParameter {
1305 optional: parameter.default.is_some(),
1306 kind: parameter.type_reflection.as_ref().map(|r| r.kind.clone()).unwrap_or_else(|| mixed_kind(false)),
1307 variadic: parameter.is_variadic,
1308 })
1309 .collect();
1310
1311 let return_kind = reflection
1312 .return_type_reflection
1313 .as_ref()
1314 .map(|r| r.type_reflection.kind.clone())
1315 .unwrap_or_else(|| mixed_kind(false));
1316
1317 TypeKind::Callable(CallableTypeKind::Closure {
1318 pure: reflection.is_pure,
1319 templates: reflection.templates.clone(),
1320 parameters,
1321 return_kind: Box::new(return_kind),
1322 })
1323 }
1324}