1use crate::wit_type::WitType;
2use crate::{InferredType, TypeInternal};
3use std::fmt;
4use std::ops::Deref;
5
6pub trait GetTypeHint {
14 fn get_type_hint(&self) -> TypeHint;
15}
16
17#[derive(PartialEq, Clone, Debug)]
18pub enum TypeHint {
19 Record(Option<Vec<(String, TypeHint)>>),
20 Tuple(Option<Vec<TypeHint>>),
21 Flag(Option<Vec<String>>),
22 Str,
23 Number,
24 List(Option<Box<TypeHint>>),
25 Boolean,
26 Option(Option<Box<TypeHint>>),
27 Enum(Option<Vec<String>>),
28 Char,
29 Result {
30 ok: Option<Box<TypeHint>>,
31 err: Option<Box<TypeHint>>,
32 },
33 Resource,
34 Variant(Option<Vec<(String, Option<TypeHint>)>>),
35 Unknown,
36 Ambiguous {
37 possibilities: Vec<TypeHint>,
38 },
39 Range,
40}
41
42impl TypeHint {
43 pub fn get_type_kind(&self) -> String {
44 match self {
45 TypeHint::Record(_) => "record".to_string(),
46 TypeHint::Tuple(_) => "tuple".to_string(),
47 TypeHint::Flag(_) => "flag".to_string(),
48 TypeHint::Str => "str".to_string(),
49 TypeHint::Number => "number".to_string(),
50 TypeHint::List(_) => "list".to_string(),
51 TypeHint::Boolean => "boolean".to_string(),
52 TypeHint::Option(_) => "option".to_string(),
53 TypeHint::Enum(_) => "enum".to_string(),
54 TypeHint::Char => "char".to_string(),
55 TypeHint::Result { .. } => "result".to_string(),
56 TypeHint::Resource => "resource".to_string(),
57 TypeHint::Variant(_) => "variant".to_string(),
58 TypeHint::Unknown => "unknown".to_string(),
59 TypeHint::Ambiguous { .. } => "ambiguous".to_string(),
60 TypeHint::Range => "range".to_string(),
61 }
62 }
63}
64
65impl fmt::Display for TypeHint {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 TypeHint::Record(Some(fields)) => {
69 write!(f, "record{{")?;
70 for (i, (name, kind)) in fields.iter().enumerate() {
71 if i > 0 {
72 write!(f, ", ")?;
73 }
74 write!(f, "{name}: {kind}")?;
75 }
76 write!(f, "}}")
77 }
78 TypeHint::Record(None) => write!(f, "record"),
79
80 TypeHint::Tuple(Some(types)) => {
81 write!(f, "tuple<")?;
82 for (i, kind) in types.iter().enumerate() {
83 if i > 0 {
84 write!(f, ", ")?;
85 }
86 write!(f, "{kind}")?;
87 }
88 write!(f, ">")
89 }
90 TypeHint::Tuple(None) => write!(f, "tuple"),
91
92 TypeHint::Flag(Some(flags)) => {
93 write!(f, "{{")?;
94 for (i, flag) in flags.iter().enumerate() {
95 if i > 0 {
96 write!(f, ", ")?;
97 }
98 write!(f, "{flag}")?;
99 }
100 write!(f, "}}")
101 }
102 TypeHint::Flag(None) => write!(f, "flag"),
103
104 TypeHint::Str => write!(f, "string"),
105 TypeHint::Number => write!(f, "number"),
106 TypeHint::List(None) => write!(f, "list"),
107 TypeHint::List(Some(typ)) => {
108 write!(f, "list<")?;
109 write!(f, "{typ}")?;
110 write!(f, ">")
111 }
112 TypeHint::Boolean => write!(f, "boolean"),
113 TypeHint::Option(None) => write!(f, "option"),
114 TypeHint::Option(Some(inner)) => {
115 write!(f, "option<")?;
116 write!(f, "{}", inner.deref())?;
117 write!(f, ">")
118 }
119 TypeHint::Enum(None) => write!(f, "enum"),
120 TypeHint::Enum(Some(enums)) => {
121 write!(f, "enum{{")?;
122 for (i, enum_name) in enums.iter().enumerate() {
123 if i > 0 {
124 write!(f, ", ")?;
125 }
126 write!(f, "{enum_name}")?;
127 }
128 write!(f, "}}")
129 }
130 TypeHint::Char => write!(f, "char"),
131 TypeHint::Result { ok, err } => {
132 write!(f, "result<")?;
133 if let Some(ok) = ok {
134 write!(f, "{ok}")?;
135 } else {
136 write!(f, "_")?;
137 }
138 write!(f, ", ")?;
139 if let Some(err) = err {
140 write!(f, "{err}")?;
141 } else {
142 write!(f, "_")?;
143 }
144 write!(f, ">")
145 }
146 TypeHint::Resource => write!(f, "resource"),
147 TypeHint::Variant(Some(variants)) => {
148 write!(f, "variant{{")?;
149 for (i, (name, kind)) in variants.iter().enumerate() {
150 if i > 0 {
151 write!(f, ", ")?;
152 }
153 write!(
154 f,
155 "{}: {}",
156 name,
157 kind.clone().map_or("_".to_string(), |x| x.to_string())
158 )?;
159 }
160 write!(f, "}}")
161 }
162 TypeHint::Variant(None) => write!(f, "variant"),
163 TypeHint::Unknown => write!(f, "unknown"),
164 TypeHint::Range => write!(f, "range"),
165
166 TypeHint::Ambiguous { possibilities } => {
167 write!(f, "conflicting types: ")?;
168 for (i, kind) in possibilities.iter().enumerate() {
169 if i > 0 {
170 write!(f, ", ")?;
171 }
172 write!(f, "{kind}")?;
173 }
174 Ok(())
175 }
176 }
177 }
178}
179
180impl GetTypeHint for WitType {
181 fn get_type_hint(&self) -> TypeHint {
182 match self {
183 WitType::Record(fields) => {
184 let fields = fields
185 .fields
186 .iter()
187 .map(|name_tpe| (name_tpe.name.clone(), name_tpe.typ.get_type_hint()))
188 .collect();
189 TypeHint::Record(Some(fields))
190 }
191 WitType::Tuple(elems) => {
192 let elems = elems.items.iter().map(|tpe| tpe.get_type_hint()).collect();
193 TypeHint::Tuple(Some(elems))
194 }
195 WitType::Flags(flags) => {
196 let flags = flags.names.clone();
197 TypeHint::Flag(Some(flags))
198 }
199 WitType::Str(_) => TypeHint::Str,
200 WitType::S8(_) => TypeHint::Number,
201 WitType::U8(_) => TypeHint::Number,
202 WitType::S16(_) => TypeHint::Number,
203 WitType::U16(_) => TypeHint::Number,
204 WitType::S32(_) => TypeHint::Number,
205 WitType::U32(_) => TypeHint::Number,
206 WitType::S64(_) => TypeHint::Number,
207 WitType::U64(_) => TypeHint::Number,
208 WitType::F32(_) => TypeHint::Number,
209 WitType::F64(_) => TypeHint::Number,
210 WitType::Chr(_) => TypeHint::Char,
211 WitType::List(tpe) => {
212 let inner = tpe.inner.get_type_hint();
213 TypeHint::List(Some(Box::new(inner)))
214 }
215 WitType::Bool(_) => TypeHint::Boolean,
216 WitType::Option(tpe) => {
217 let inner = tpe.inner.get_type_hint();
218 TypeHint::Option(Some(Box::new(inner)))
219 }
220 WitType::Enum(tpe) => {
221 let variants = tpe.cases.clone();
222 TypeHint::Enum(Some(variants))
223 }
224 WitType::Result(tpe_result) => {
225 let ok: &Option<Box<WitType>> = &tpe_result.ok;
226 let err: &Option<Box<WitType>> = &tpe_result.err;
227 let ok = ok.as_ref().map(|tpe| tpe.get_type_hint());
228 let err = err.as_ref().map(|tpe| tpe.get_type_hint());
229 TypeHint::Result {
230 ok: ok.map(Box::new),
231 err: err.map(Box::new),
232 }
233 }
234 WitType::Handle(_) => TypeHint::Resource,
235 WitType::Variant(variants) => {
236 let variants = variants
237 .cases
238 .iter()
239 .map(|name_tpe| {
240 (
241 name_tpe.name.clone(),
242 name_tpe.typ.clone().map(|tpe| tpe.get_type_hint()),
243 )
244 })
245 .collect();
246 TypeHint::Variant(Some(variants))
247 }
248 }
249 }
250}
251
252impl GetTypeHint for InferredType {
253 fn get_type_hint(&self) -> TypeHint {
254 match self.internal_type() {
255 TypeInternal::Bool => TypeHint::Boolean,
256 TypeInternal::S8
257 | TypeInternal::U8
258 | TypeInternal::S16
259 | TypeInternal::U16
260 | TypeInternal::S32
261 | TypeInternal::U32
262 | TypeInternal::S64
263 | TypeInternal::U64
264 | TypeInternal::F32
265 | TypeInternal::F64 => TypeHint::Number,
266 TypeInternal::Chr => TypeHint::Char,
267 TypeInternal::Str => TypeHint::Str,
268 TypeInternal::List(inferred_type) => {
269 TypeHint::List(Some(Box::new(inferred_type.get_type_hint())))
270 }
271 TypeInternal::Tuple(tuple) => {
272 TypeHint::Tuple(Some(tuple.iter().map(GetTypeHint::get_type_hint).collect()))
273 }
274 TypeInternal::Record(record) => TypeHint::Record(Some(
275 record
276 .iter()
277 .map(|(name, tpe)| (name.to_string(), tpe.get_type_hint()))
278 .collect(),
279 )),
280 TypeInternal::Flags(flags) => {
281 TypeHint::Flag(Some(flags.iter().map(|x| x.to_string()).collect()))
282 }
283 TypeInternal::Enum(enums) => {
284 TypeHint::Enum(Some(enums.iter().map(|s| s.to_string()).collect()))
285 }
286 TypeInternal::Option(inner) => TypeHint::Option(Some(Box::new(inner.get_type_hint()))),
287 TypeInternal::Result { ok, error } => TypeHint::Result {
288 ok: ok.as_ref().map(|tpe| Box::new(tpe.get_type_hint())),
289 err: error.as_ref().map(|tpe| Box::new(tpe.get_type_hint())),
290 },
291 TypeInternal::Variant(variants) => TypeHint::Variant(Some(
292 variants
293 .iter()
294 .map(|(name, tpe)| {
295 (
296 name.to_string(),
297 tpe.as_ref().map(GetTypeHint::get_type_hint),
298 )
299 })
300 .collect(),
301 )),
302 TypeInternal::Resource { .. } => TypeHint::Resource,
303 TypeInternal::AllOf(possibilities) => get_type_kind(possibilities),
304 TypeInternal::Unknown | TypeInternal::Sequence(_) | TypeInternal::Instance { .. } => {
305 TypeHint::Unknown
306 }
307 TypeInternal::Range { .. } => TypeHint::Range,
308 }
309 }
310}
311
312fn get_type_kind(possibilities: &[InferredType]) -> TypeHint {
313 if let Some(first) = possibilities.first() {
314 let first = first.get_type_hint();
315 if possibilities.iter().all(|p| p.get_type_hint() == first) {
316 first
317 } else {
318 TypeHint::Ambiguous {
319 possibilities: possibilities.iter().map(|p| p.get_type_hint()).collect(),
320 }
321 }
322 } else {
323 TypeHint::Unknown
324 }
325}