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 { format!("non-empty-list<{}>", value) } else { format!("list<{}>", value) }
820 }
821 ArrayTypeKind::CallableArray => "callable-array".to_string(),
822 ArrayTypeKind::Shape(array_shape) => {
823 let mut properties = array_shape
824 .properties
825 .iter()
826 .map(|property| {
827 let kind = property.kind.get_key(interner);
828
829 if let Some(key) = property.key.as_ref() {
830 let key = key.get_key(interner);
831
832 if property.optional {
833 format!("{}?: {}", key, kind)
834 } else {
835 format!("{}: {}", key, kind)
836 }
837 } else {
838 kind
839 }
840 })
841 .collect::<Vec<_>>()
842 .join(", ");
843
844 if let Some((key, value)) = &array_shape.additional_properties {
845 if matches!(
846 (key.as_ref(), value.as_ref()),
847 (TypeKind::Scalar(ScalarTypeKind::ArrayKey), TypeKind::Mixed { .. })
848 ) {
849 properties.push_str(", ...");
850 } else {
851 let key = key.get_key(interner);
852 let value = value.get_key(interner);
853
854 properties.push_str(&format!(", ...array<{}: {}>", key, value));
855 }
856 }
857
858 format!("array{{{}}}", properties)
859 }
860 },
861 TypeKind::Callable(callable_type_kind) => match &callable_type_kind {
862 CallableTypeKind::Callable { pure, templates, parameters, return_kind } => {
863 let parameters = parameters
864 .iter()
865 .map(|parameter| {
866 let mut kind = parameter.kind.get_key(interner);
867 if parameter.optional {
868 kind.push('=');
869 }
870
871 if parameter.variadic {
872 kind.push_str("...");
873 }
874
875 kind
876 })
877 .collect::<Vec<_>>()
878 .join(", ");
879
880 let return_kind = return_kind.get_key(interner);
881
882 let templates =
883 templates.iter().map(|template| template.get_key(interner)).collect::<Vec<_>>().join(", ");
884 let templates = if !templates.is_empty() { format!("<{}>", templates) } else { "".to_string() };
885
886 if *pure {
887 format!("(pure-callable{}({}): {})", templates, parameters, return_kind)
888 } else {
889 format!("(callable{}({}): {})", templates, parameters, return_kind)
890 }
891 }
892 CallableTypeKind::Closure { pure, templates, parameters, return_kind } => {
893 let parameters = parameters
894 .iter()
895 .map(|parameter| {
896 let mut kind = parameter.kind.get_key(interner);
897 if parameter.optional {
898 kind.push('=');
899 }
900
901 if parameter.variadic {
902 kind.push_str("...");
903 }
904
905 kind
906 })
907 .collect::<Vec<_>>()
908 .join(", ");
909
910 let return_kind = return_kind.get_key(interner);
911
912 let templates =
913 templates.iter().map(|template| template.get_key(interner)).collect::<Vec<_>>().join(", ");
914 let templates = if !templates.is_empty() { format!("<{}>", templates) } else { "".to_string() };
915
916 if *pure {
917 format!("(pure-Closure{}({}): {})", templates, parameters, return_kind)
918 } else {
919 format!("(Closure{}({}): {})", templates, parameters, return_kind)
920 }
921 }
922 },
923 TypeKind::Value(value_type_kind) => match &value_type_kind {
924 ValueTypeKind::String { value, .. } => {
925 format!("\"{}\"", value)
926 }
927 ValueTypeKind::Integer { value } => value.to_string(),
928 ValueTypeKind::Float { value } => value.to_string(),
929 ValueTypeKind::Null => "null".to_string(),
930 ValueTypeKind::True => "true".to_string(),
931 ValueTypeKind::False => "false".to_string(),
932 ValueTypeKind::ClassLikeConstant { class_like, constant } => {
933 format!("{}::{}", class_like.get_key(interner), interner.lookup(constant))
934 }
935 },
936 TypeKind::Conditional { parameter, condition, then, otherwise } => {
937 let parameter = parameter.get_key(interner);
938 let condition = condition.get_key(interner);
939 let then = then.get_key(interner);
940 let otherwise = otherwise.get_key(interner);
941
942 format!("{} is {} ? {} : {}", parameter, condition, then, otherwise)
943 }
944 TypeKind::KeyOf { kind } => {
945 let kind = kind.get_key(interner);
946
947 format!("key-of<{}>", kind)
948 }
949 TypeKind::ValueOf { kind } => {
950 let kind = kind.get_key(interner);
951
952 format!("value-of<{}>", kind)
953 }
954 TypeKind::PropertiesOf { kind } => {
955 let kind = kind.get_key(interner);
956
957 format!("properties-of<{}>", kind)
958 }
959 TypeKind::ClassStringMap { key, value_kind } => {
960 let mut template = interner.lookup(&key.name).to_owned();
961 for constraint in &key.constraints {
962 template.push_str(&format!(" of {}", constraint.get_key(interner)));
963 }
964
965 let value_kind = value_kind.get_key(interner);
966
967 format!("class-string-map<{}, {}>", template, value_kind)
968 }
969 TypeKind::Index { base_kind, index_kind } => {
970 let base_kind = base_kind.get_key(interner);
971 let index_kind = index_kind.get_key(interner);
972
973 format!("{}[{}]", base_kind, index_kind)
974 }
975 TypeKind::Variable { name } => interner.lookup(name).to_owned(),
976 TypeKind::Iterable { key, value } => {
977 let key = key.get_key(interner);
978 let value = value.get_key(interner);
979
980 format!("iterable<{}, {}>", key, value)
981 }
982 TypeKind::Void => "void".to_string(),
983 TypeKind::Resource => "resource".to_string(),
984 TypeKind::ClosedResource => "closed-resource".to_string(),
985 TypeKind::Mixed { explicit } => {
986 if *explicit {
987 "mixed".to_string()
988 } else {
989 "unknown".to_string()
990 }
991 }
992 TypeKind::Never => "never".to_string(),
993 TypeKind::GenericParameter { name, defined_in, .. } => {
994 format!("{}:{}", interner.lookup(name), interner.lookup(defined_in))
995 }
996 }
997 }
998}
999
1000pub fn bool_kind() -> TypeKind {
1002 TypeKind::Scalar(ScalarTypeKind::Bool)
1003}
1004
1005pub fn integer_kind() -> TypeKind {
1007 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: None })
1008}
1009
1010pub fn positive_integer_kind() -> TypeKind {
1011 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(1), max: None })
1012}
1013
1014pub fn non_negative_integer_kind() -> TypeKind {
1015 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(0), max: None })
1016}
1017
1018pub fn negative_integer_kind() -> TypeKind {
1019 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(-1) })
1020}
1021
1022pub fn non_positive_integer_kind() -> TypeKind {
1023 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(0) })
1024}
1025
1026pub fn minimum_integer_kind(min: isize) -> TypeKind {
1027 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(min), max: None })
1028}
1029
1030pub fn maximum_integer_kind(max: isize) -> TypeKind {
1031 TypeKind::Scalar(ScalarTypeKind::Integer { min: None, max: Some(max) })
1032}
1033
1034pub fn integer_range_kind(min: isize, max: isize) -> TypeKind {
1035 TypeKind::Scalar(ScalarTypeKind::Integer { min: Some(min), max: Some(max) })
1036}
1037
1038pub fn float_kind() -> TypeKind {
1040 TypeKind::Scalar(ScalarTypeKind::Float)
1041}
1042
1043pub fn string_kind() -> TypeKind {
1045 TypeKind::Scalar(ScalarTypeKind::String)
1046}
1047
1048pub fn non_empty_string_kind() -> TypeKind {
1050 TypeKind::Scalar(ScalarTypeKind::NonEmptyString)
1051}
1052
1053pub fn list_kind(value: TypeKind, known_size: Option<usize>) -> TypeKind {
1055 TypeKind::Array(ArrayTypeKind::List { non_empty: false, value: Box::new(value), known_size })
1056}
1057
1058pub fn array_kind(key: TypeKind, value: TypeKind, known_size: Option<usize>) -> TypeKind {
1060 TypeKind::Array(ArrayTypeKind::Array { non_empty: false, key: Box::new(key), value: Box::new(value), known_size })
1061}
1062
1063pub fn non_empty_list_kind(value: TypeKind, known_size: Option<usize>) -> TypeKind {
1065 TypeKind::Array(ArrayTypeKind::List { non_empty: true, value: Box::new(value), known_size })
1066}
1067
1068pub fn non_empty_array_kind(key: TypeKind, value: TypeKind, known_size: Option<usize>) -> TypeKind {
1070 TypeKind::Array(ArrayTypeKind::Array { non_empty: true, key: Box::new(key), value: Box::new(value), known_size })
1071}
1072
1073pub fn indexed_shape_property(kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1074 ArrayShapeProperty { key: None, kind, optional }
1075}
1076
1077pub fn string_shape_property(key: StringIdentifier, kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1078 ArrayShapeProperty { key: Some(ArrayShapePropertyKey::String(key)), kind, optional }
1079}
1080
1081pub fn integer_shape_property(key: isize, kind: TypeKind, optional: bool) -> ArrayShapeProperty {
1082 ArrayShapeProperty { key: Some(ArrayShapePropertyKey::Integer(key)), kind, optional }
1083}
1084
1085pub fn array_shape_kind(
1086 properties: Vec<ArrayShapeProperty>,
1087 additional_properties: Option<(TypeKind, TypeKind)>,
1088) -> TypeKind {
1089 TypeKind::Array(ArrayTypeKind::Shape(ArrayShape {
1090 properties,
1091 additional_properties: additional_properties.map(|(k, v)| (Box::new(k), Box::new(v))),
1092 }))
1093}
1094
1095pub fn mixed_kind(explicit: bool) -> TypeKind {
1097 TypeKind::Mixed { explicit }
1098}
1099
1100pub fn union_kind(kinds: Vec<TypeKind>) -> TypeKind {
1102 TypeKind::Union { kinds }
1103}
1104
1105pub fn intersection_kind(kinds: Vec<TypeKind>) -> TypeKind {
1107 TypeKind::Intersection { kinds }
1108}
1109
1110pub fn callable_parameter(kind: TypeKind, optional: bool, variadic: bool) -> CallableParameter {
1112 CallableParameter { kind, optional, variadic }
1113}
1114
1115pub fn any_callable_kind() -> TypeKind {
1118 callable_kind(false, vec![], vec![callable_parameter(mixed_kind(false), true, true)], mixed_kind(false))
1119}
1120
1121pub fn callable_kind(
1123 pure: bool,
1124 templates: Vec<Template>,
1125 parameters: Vec<CallableParameter>,
1126 return_kind: TypeKind,
1127) -> TypeKind {
1128 TypeKind::Callable(CallableTypeKind::Callable { pure, templates, parameters, return_kind: Box::new(return_kind) })
1129}
1130
1131pub fn any_closure_kind() -> TypeKind {
1134 closure_kind(false, vec![], vec![callable_parameter(mixed_kind(false), true, true)], mixed_kind(false))
1135}
1136
1137pub fn closure_kind(
1139 pure: bool,
1140 templates: Vec<Template>,
1141 parameters: Vec<CallableParameter>,
1142 return_kind: TypeKind,
1143) -> TypeKind {
1144 TypeKind::Callable(CallableTypeKind::Closure { pure, templates, parameters, return_kind: Box::new(return_kind) })
1145}
1146
1147pub fn variable_kind(name: StringIdentifier) -> TypeKind {
1149 TypeKind::Variable { name }
1150}
1151
1152pub fn value_string_kind(
1154 value: StringIdentifier,
1155 length: usize,
1156 is_uppercase: Trinary,
1157 is_ascii_uppercase: Trinary,
1158 is_lowercase: Trinary,
1159 is_ascii_lowercase: Trinary,
1160) -> TypeKind {
1161 TypeKind::Value(ValueTypeKind::String {
1162 value,
1163 length,
1164 is_uppercase,
1165 is_lowercase,
1166 is_ascii_uppercase,
1167 is_ascii_lowercase,
1168 })
1169}
1170
1171pub fn value_integer_kind(value: i64) -> TypeKind {
1173 TypeKind::Value(ValueTypeKind::Integer { value })
1174}
1175
1176pub fn value_float_kind(value: OrderedFloat<f64>) -> TypeKind {
1178 TypeKind::Value(ValueTypeKind::Float { value })
1179}
1180
1181pub fn null_kind() -> TypeKind {
1183 TypeKind::Value(ValueTypeKind::Null)
1184}
1185
1186pub fn true_kind() -> TypeKind {
1188 TypeKind::Value(ValueTypeKind::True)
1189}
1190
1191pub fn false_kind() -> TypeKind {
1193 TypeKind::Value(ValueTypeKind::False)
1194}
1195
1196pub fn iterable_kind(key_kind: TypeKind, value_kind: TypeKind) -> TypeKind {
1198 TypeKind::Iterable { key: Box::new(key_kind), value: Box::new(value_kind) }
1199}
1200
1201pub fn any_object_kind() -> TypeKind {
1203 TypeKind::Object(ObjectTypeKind::AnyObject)
1204}
1205
1206pub fn static_kind(scope: StringIdentifier) -> TypeKind {
1208 TypeKind::Object(ObjectTypeKind::Static { scope })
1209}
1210
1211pub fn parent_kind(scope: StringIdentifier) -> TypeKind {
1213 TypeKind::Object(ObjectTypeKind::Parent { scope })
1214}
1215
1216pub fn self_kind(scope: StringIdentifier) -> TypeKind {
1218 TypeKind::Object(ObjectTypeKind::Self_ { scope })
1219}
1220
1221pub fn named_object_kind(name: StringIdentifier, type_parameters: Vec<TypeKind>) -> TypeKind {
1223 TypeKind::Object(ObjectTypeKind::NamedObject { name, type_parameters })
1224}
1225
1226pub fn anonymous_object_kind(span: Span) -> TypeKind {
1228 TypeKind::Object(ObjectTypeKind::AnonymousObject { span })
1229}
1230
1231pub fn enum_case_kind(enum_name: StringIdentifier, case_name: StringIdentifier) -> TypeKind {
1232 TypeKind::Object(ObjectTypeKind::EnumCase { enum_name, case_name })
1233}
1234
1235pub fn void_kind() -> TypeKind {
1237 TypeKind::Void
1238}
1239
1240pub fn never_kind() -> TypeKind {
1242 TypeKind::Never
1243}
1244
1245pub fn resource_kind() -> TypeKind {
1247 TypeKind::Resource
1248}
1249
1250pub fn closed_resource_kind() -> TypeKind {
1252 TypeKind::ClosedResource
1253}
1254
1255pub fn key_of_kind(kind: TypeKind) -> TypeKind {
1257 TypeKind::KeyOf { kind: Box::new(kind) }
1258}
1259
1260pub fn value_of_kind(kind: TypeKind) -> TypeKind {
1262 TypeKind::ValueOf { kind: Box::new(kind) }
1263}
1264
1265pub fn properties_of_kind(kind: TypeKind) -> TypeKind {
1267 TypeKind::PropertiesOf { kind: Box::new(kind) }
1268}
1269
1270pub fn conditional_kind(parameter: TypeKind, condition: TypeKind, then: TypeKind, otherwise: TypeKind) -> TypeKind {
1272 TypeKind::Conditional {
1273 parameter: Box::new(parameter),
1274 condition: Box::new(condition),
1275 then: Box::new(then),
1276 otherwise: Box::new(otherwise),
1277 }
1278}
1279
1280pub fn class_string_map_kind(key_template: Template, value_kind: TypeKind) -> TypeKind {
1282 TypeKind::ClassStringMap { key: key_template, value_kind: Box::new(value_kind) }
1283}
1284
1285pub fn index_kind(base_kind: TypeKind, index_kind: TypeKind) -> TypeKind {
1287 TypeKind::Index { base_kind: Box::new(base_kind), index_kind: Box::new(index_kind) }
1288}
1289
1290pub fn array_key_kind() -> TypeKind {
1292 TypeKind::Scalar(ScalarTypeKind::ArrayKey)
1293}
1294
1295impl From<&FunctionLikeReflection> for TypeKind {
1296 fn from(reflection: &FunctionLikeReflection) -> Self {
1297 let parameters: Vec<_> = reflection
1298 .parameters
1299 .iter()
1300 .map(|parameter| CallableParameter {
1301 optional: parameter.default.is_some(),
1302 kind: parameter.type_reflection.as_ref().map(|r| r.kind.clone()).unwrap_or_else(|| mixed_kind(false)),
1303 variadic: parameter.is_variadic,
1304 })
1305 .collect();
1306
1307 let return_kind = reflection
1308 .return_type_reflection
1309 .as_ref()
1310 .map(|r| r.type_reflection.kind.clone())
1311 .unwrap_or_else(|| mixed_kind(false));
1312
1313 TypeKind::Callable(CallableTypeKind::Closure {
1314 pure: reflection.is_pure,
1315 templates: reflection.templates.clone(),
1316 parameters,
1317 return_kind: Box::new(return_kind),
1318 })
1319 }
1320}