1use crate::atomic::Atomic;
10use crate::union::Type;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum SimpleType {
16 String,
17 Int,
18 Float,
19 Bool,
20 Mixed,
21 Null,
22 Void,
23 Never,
24 Complex(Box<Type>),
26}
27
28impl SimpleType {
29 pub fn from_union(u: Type) -> Self {
31 if !u.possibly_undefined
33 && !u.from_docblock
34 && !u.falsy_stripped
35 && !u.possibly_absent_offset
36 && u.types.len() == 1
37 {
38 match &u.types[0] {
39 Atomic::TString => return Self::String,
40 Atomic::TInt => return Self::Int,
41 Atomic::TFloat | Atomic::TIntegralFloat => return Self::Float,
42 Atomic::TBool => return Self::Bool,
43 Atomic::TMixed => return Self::Mixed,
44 Atomic::TNull => return Self::Null,
45 Atomic::TVoid => return Self::Void,
46 Atomic::TNever => return Self::Never,
47 _ => {}
48 }
49 }
50 Self::Complex(Box::new(u))
51 }
52
53 pub fn to_union(&self) -> Type {
55 match self {
56 Self::String => Type::string(),
57 Self::Int => Type::int(),
58 Self::Float => Type::float(),
59 Self::Bool => Type::bool(),
60 Self::Mixed => Type::mixed(),
61 Self::Null => Type::null(),
62 Self::Void => Type::void(),
63 Self::Never => Type::never(),
64 Self::Complex(u) => *u.clone(),
65 }
66 }
67
68 pub fn is_simple(&self) -> bool {
70 !matches!(self, Self::Complex(_))
71 }
72
73 pub fn as_complex(&self) -> Option<&Type> {
75 match self {
76 Self::Complex(u) => Some(u),
77 _ => None,
78 }
79 }
80}
81
82impl fmt::Display for SimpleType {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 match self {
85 Self::String => write!(f, "string"),
86 Self::Int => write!(f, "int"),
87 Self::Float => write!(f, "float"),
88 Self::Bool => write!(f, "bool"),
89 Self::Mixed => write!(f, "mixed"),
90 Self::Null => write!(f, "null"),
91 Self::Void => write!(f, "void"),
92 Self::Never => write!(f, "never"),
93 Self::Complex(u) => write!(f, "{}", u),
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn simple_scalar_roundtrip() {
104 let u = Type::string();
105 let s = SimpleType::from_union(u.clone());
106 assert_eq!(s, SimpleType::String);
107 assert_eq!(s.to_union(), u);
108 }
109
110 #[test]
111 fn nullable_scalar_is_complex() {
112 let u = Type::nullable(Atomic::TString);
113 let s = SimpleType::from_union(u.clone());
114 assert_eq!(s, SimpleType::Complex(Box::new(u.clone())));
115 assert_eq!(s.to_union(), u);
116 }
117}