1use crate::{GetTypeHint, InferredType, InstanceType, TypeInternal};
16use bincode::{Decode, Encode};
17use golem_wasm_ast::analysis::analysed_type::{bool, field, record, str, tuple};
18use golem_wasm_ast::analysis::{
19 AnalysedResourceId, AnalysedResourceMode, AnalysedType, NameOptionTypePair, NameTypePair,
20 TypeBool, TypeChr, TypeEnum, TypeF32, TypeF64, TypeFlags, TypeHandle, TypeList, TypeOption,
21 TypeRecord, TypeResult, TypeS16, TypeS32, TypeS64, TypeS8, TypeStr, TypeTuple, TypeU16,
22 TypeU32, TypeU64, TypeU8, TypeVariant,
23};
24use serde::{Deserialize, Serialize};
25
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode)]
30pub enum AnalysedTypeWithUnit {
31 Unit,
32 Type(AnalysedType),
33}
34
35impl AnalysedTypeWithUnit {
36 pub fn unit() -> Self {
37 AnalysedTypeWithUnit::Unit
38 }
39
40 pub fn analysed_type(typ: AnalysedType) -> Self {
41 AnalysedTypeWithUnit::Type(typ)
42 }
43}
44
45impl TryFrom<AnalysedTypeWithUnit> for AnalysedType {
46 type Error = String;
47
48 fn try_from(value: AnalysedTypeWithUnit) -> Result<Self, Self::Error> {
49 match value {
50 AnalysedTypeWithUnit::Unit => Ok(tuple(vec![])),
51 AnalysedTypeWithUnit::Type(typ) => Ok(typ),
52 }
53 }
54}
55
56impl TryFrom<&InferredType> for AnalysedType {
57 type Error = String;
58
59 fn try_from(value: &InferredType) -> Result<Self, Self::Error> {
60 let with_unit = AnalysedTypeWithUnit::try_from(value)?;
61 AnalysedType::try_from(with_unit)
62 }
63}
64
65impl TryFrom<&InferredType> for AnalysedTypeWithUnit {
66 type Error = String;
67
68 fn try_from(inferred_type: &InferredType) -> Result<Self, Self::Error> {
69 match inferred_type.internal_type() {
70 TypeInternal::Instance { instance_type } => match instance_type.as_ref() {
71 InstanceType::Resource {
72 analysed_resource_id,
73 analysed_resource_mode,
74 ..
75 } => {
76 let analysed_resource_id = AnalysedResourceId(*analysed_resource_id);
77
78 let analysed_resource_mode = if *analysed_resource_mode == 0 {
79 AnalysedResourceMode::Owned
80 } else {
81 AnalysedResourceMode::Borrowed
82 };
83
84 Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Handle(
85 TypeHandle {
86 resource_id: analysed_resource_id,
87 mode: analysed_resource_mode,
88 name: None,
89 owner: None,
90 },
91 )))
92 }
93
94 _ => Ok(AnalysedTypeWithUnit::analysed_type(str())),
95 },
96 TypeInternal::Range { from, to } => {
97 let from: AnalysedType = AnalysedType::try_from(from)?;
98 let to: Option<AnalysedType> =
99 to.as_ref().map(AnalysedType::try_from).transpose()?;
100 let analysed_type = match (from, to) {
101 (from_type, Some(to_type)) => record(vec![
102 field("from", from_type),
103 field("to", to_type),
104 field("inclusive", bool()),
105 ]),
106
107 (from_type, None) => {
108 record(vec![field("from", from_type), field("inclusive", bool())])
109 }
110 };
111 Ok(AnalysedTypeWithUnit::analysed_type(analysed_type))
112 }
113 TypeInternal::Bool => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Bool(
114 TypeBool,
115 ))),
116 TypeInternal::S8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S8(
117 TypeS8,
118 ))),
119 TypeInternal::U8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U8(
120 TypeU8,
121 ))),
122 TypeInternal::S16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S16(
123 TypeS16,
124 ))),
125 TypeInternal::U16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U16(
126 TypeU16,
127 ))),
128 TypeInternal::S32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S32(
129 TypeS32,
130 ))),
131 TypeInternal::U32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U32(
132 TypeU32,
133 ))),
134 TypeInternal::S64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S64(
135 TypeS64,
136 ))),
137 TypeInternal::U64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U64(
138 TypeU64,
139 ))),
140 TypeInternal::F32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F32(
141 TypeF32,
142 ))),
143 TypeInternal::F64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F64(
144 TypeF64,
145 ))),
146 TypeInternal::Chr => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Chr(
147 TypeChr,
148 ))),
149 TypeInternal::Str => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Str(
150 TypeStr,
151 ))),
152 TypeInternal::List(inferred_type) => Ok(AnalysedTypeWithUnit::analysed_type(
153 AnalysedType::List(TypeList {
154 inner: Box::new(inferred_type.try_into()?),
155 name: None,
156 owner: None,
157 }),
158 )),
159 TypeInternal::Tuple(tuple) => Ok(AnalysedTypeWithUnit::analysed_type(
160 AnalysedType::Tuple(TypeTuple {
161 items: tuple
162 .iter()
163 .map(|t| t.try_into())
164 .collect::<Result<Vec<AnalysedType>, String>>()?,
165 name: None,
166 owner: None,
167 }),
168 )),
169 TypeInternal::Record(record) => Ok(AnalysedTypeWithUnit::analysed_type(
170 AnalysedType::Record(TypeRecord {
171 fields: record
172 .iter()
173 .map(|(name, typ)| {
174 Ok(NameTypePair {
175 name: name.to_string(),
176 typ: typ.try_into()?,
177 })
178 })
179 .collect::<Result<Vec<NameTypePair>, String>>()?,
180 name: None,
181 owner: None,
182 }),
183 )),
184 TypeInternal::Flags(flags) => Ok(AnalysedTypeWithUnit::analysed_type(
185 AnalysedType::Flags(TypeFlags {
186 names: flags.clone(),
187 name: None,
188 owner: None,
189 }),
190 )),
191 TypeInternal::Enum(enums) => Ok(AnalysedTypeWithUnit::analysed_type(
192 AnalysedType::Enum(TypeEnum {
193 cases: enums.clone(),
194 name: None,
195 owner: None,
196 }),
197 )),
198 TypeInternal::Option(option) => Ok(AnalysedTypeWithUnit::analysed_type(
199 AnalysedType::Option(TypeOption {
200 inner: Box::new(option.try_into()?),
201 name: None,
202 owner: None,
203 }),
204 )),
205 TypeInternal::Result { ok, error } => Ok(AnalysedTypeWithUnit::analysed_type(
206 AnalysedType::Result(TypeResult {
208 ok: ok.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
209 err: error.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
210 name: None,
211 owner: None,
212 }),
213 )),
214 TypeInternal::Variant(variant) => Ok(AnalysedTypeWithUnit::analysed_type(
215 AnalysedType::Variant(TypeVariant {
216 cases: variant
217 .iter()
218 .map(|(name, typ)| {
219 Ok(NameOptionTypePair {
220 name: name.clone(),
221 typ: typ.as_ref().map(|t| t.try_into()).transpose()?,
222 })
223 })
224 .collect::<Result<Vec<NameOptionTypePair>, String>>()?,
225 name: None,
226 owner: None,
227 }),
228 )),
229 TypeInternal::Resource {
230 resource_id,
231 resource_mode,
232 name: _,
233 owner: _,
234 } => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Handle(
235 TypeHandle {
236 resource_id: AnalysedResourceId(*resource_id),
237 mode: if resource_mode == &0 {
238 AnalysedResourceMode::Owned
239 } else {
240 AnalysedResourceMode::Borrowed
241 },
242 name: None,
243 owner: None,
244 },
245 ))),
246
247 TypeInternal::AllOf(types) => Err(format!(
248 "ambiguous types {}",
249 types
250 .iter()
251 .map(|x| x.get_type_hint().to_string())
252 .collect::<Vec<_>>()
253 .join(", ")
254 )),
255 TypeInternal::Unknown => Err("failed to infer type".to_string()),
256 TypeInternal::Sequence(vec) => {
259 if vec.is_empty() {
260 Ok(AnalysedTypeWithUnit::unit())
261 } else if vec.len() == 1 {
262 let first = &vec[0];
263 Ok(first.try_into()?)
264 } else {
265 Err("function with multiple return types not supported".to_string())
266 }
267 }
268 }
269 }
270}