1use std::fmt;
2use ustr::Ustr;
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub enum Ty {
6 Void,
7 Boolean,
8 Byte,
9 Char,
10 Short,
11 Int,
12 Long,
13 Float,
14 Double,
15 Class(Ustr),
16 Array(Box<Ty>),
17 TypeVar(Ustr),
18 Wildcard(Option<Box<Ty>>),
19 Intersection(Vec<Ty>),
20}
21
22impl Ty {
23 pub fn object() -> Self {
24 Ty::Class(Ustr::from("java/lang/Object"))
25 }
26
27 pub fn string() -> Self {
28 Ty::Class(Ustr::from("java/lang/String"))
29 }
30
31 pub fn class(internal_name: impl AsRef<str>) -> Self {
32 Ty::Class(Ustr::from(internal_name.as_ref()))
33 }
34
35 pub fn is_string(&self) -> bool {
36 matches!(self.erasure(), Ty::Class(name) if name.as_str() == "java/lang/String")
37 }
38
39 pub fn descriptor(&self) -> String {
40 match self {
41 Ty::Void => "V".to_string(),
42 Ty::Boolean => "Z".to_string(),
43 Ty::Byte => "B".to_string(),
44 Ty::Char => "C".to_string(),
45 Ty::Short => "S".to_string(),
46 Ty::Int => "I".to_string(),
47 Ty::Long => "J".to_string(),
48 Ty::Float => "F".to_string(),
49 Ty::Double => "D".to_string(),
50 Ty::Class(name) => format!("L{};", name.as_str().replace('.', "/")),
51 Ty::Array(elem) => format!("[{}", elem.descriptor()),
52 Ty::TypeVar(_) => "Ljava/lang/Object;".to_string(),
53 Ty::Wildcard(_) => "Ljava/lang/Object;".to_string(),
54 Ty::Intersection(_) => "Ljava/lang/Object;".to_string(),
55 }
56 }
57
58 pub fn erasure(&self) -> Ty {
59 match self {
60 Ty::TypeVar(_) => Ty::object(),
61 Ty::Wildcard(Some(bound)) => bound.erasure(),
62 Ty::Wildcard(None) => Ty::object(),
63 Ty::Intersection(types) => types
64 .first()
65 .map(|t| t.erasure())
66 .unwrap_or_else(Ty::object),
67 other => other.clone(),
68 }
69 }
70
71 pub fn is_primitive(&self) -> bool {
72 matches!(
73 self,
74 Ty::Boolean
75 | Ty::Byte
76 | Ty::Char
77 | Ty::Short
78 | Ty::Int
79 | Ty::Long
80 | Ty::Float
81 | Ty::Double
82 )
83 }
84
85 pub fn is_numeric(&self) -> bool {
86 matches!(
87 self,
88 Ty::Byte | Ty::Short | Ty::Int | Ty::Long | Ty::Float | Ty::Double | Ty::Char
89 )
90 }
91
92 pub fn is_integral(&self) -> bool {
93 matches!(self, Ty::Byte | Ty::Short | Ty::Int | Ty::Long | Ty::Char)
94 }
95
96 pub fn is_floating(&self) -> bool {
97 matches!(self, Ty::Float | Ty::Double)
98 }
99
100 pub fn size(&self) -> usize {
101 match self {
102 Ty::Long | Ty::Double => 2,
103 Ty::Void => 0,
104 _ => 1,
105 }
106 }
107
108 pub fn internal_name(&self) -> String {
109 match self {
110 Ty::Class(name) => name.as_str().to_string(),
111 Ty::Array(elem) => elem.descriptor(),
112 _ => self.erasure().internal_name(),
113 }
114 }
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Hash)]
118pub struct TypeParam {
119 pub name: Ustr,
120 pub bounds: Vec<Ty>,
121}
122
123impl fmt::Display for Ty {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 match self {
126 Ty::Void => write!(f, "void"),
127 Ty::Boolean => write!(f, "boolean"),
128 Ty::Byte => write!(f, "byte"),
129 Ty::Char => write!(f, "char"),
130 Ty::Short => write!(f, "short"),
131 Ty::Int => write!(f, "int"),
132 Ty::Long => write!(f, "long"),
133 Ty::Float => write!(f, "float"),
134 Ty::Double => write!(f, "double"),
135 Ty::Class(name) => write!(f, "{}", name.as_str().replace('/', ".")),
136 Ty::Array(elem) => write!(f, "{}[]", elem),
137 Ty::TypeVar(name) => write!(f, "{}", name.as_str()),
138 Ty::Wildcard(Some(bound)) => write!(f, "? extends {}", bound),
139 Ty::Wildcard(None) => write!(f, "?"),
140 Ty::Intersection(types) => {
141 let parts: Vec<String> = types.iter().map(|t| t.to_string()).collect();
142 write!(f, "{}", parts.join(" & "))
143 }
144 }
145 }
146}