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 },
89 )))
90 }
91
92 _ => Ok(AnalysedTypeWithUnit::analysed_type(str())),
93 },
94 TypeInternal::Range { from, to } => {
95 let from: AnalysedType = AnalysedType::try_from(from)?;
96 let to: Option<AnalysedType> =
97 to.as_ref().map(AnalysedType::try_from).transpose()?;
98 let analysed_type = match (from, to) {
99 (from_type, Some(to_type)) => record(vec![
100 field("from", from_type),
101 field("to", to_type),
102 field("inclusive", bool()),
103 ]),
104
105 (from_type, None) => {
106 record(vec![field("from", from_type), field("inclusive", bool())])
107 }
108 };
109 Ok(AnalysedTypeWithUnit::analysed_type(analysed_type))
110 }
111 TypeInternal::Bool => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Bool(
112 TypeBool,
113 ))),
114 TypeInternal::S8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S8(
115 TypeS8,
116 ))),
117 TypeInternal::U8 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U8(
118 TypeU8,
119 ))),
120 TypeInternal::S16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S16(
121 TypeS16,
122 ))),
123 TypeInternal::U16 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U16(
124 TypeU16,
125 ))),
126 TypeInternal::S32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S32(
127 TypeS32,
128 ))),
129 TypeInternal::U32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U32(
130 TypeU32,
131 ))),
132 TypeInternal::S64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::S64(
133 TypeS64,
134 ))),
135 TypeInternal::U64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::U64(
136 TypeU64,
137 ))),
138 TypeInternal::F32 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F32(
139 TypeF32,
140 ))),
141 TypeInternal::F64 => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::F64(
142 TypeF64,
143 ))),
144 TypeInternal::Chr => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Chr(
145 TypeChr,
146 ))),
147 TypeInternal::Str => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Str(
148 TypeStr,
149 ))),
150 TypeInternal::List(inferred_type) => Ok(AnalysedTypeWithUnit::analysed_type(
151 AnalysedType::List(TypeList {
152 inner: Box::new(inferred_type.try_into()?),
153 }),
154 )),
155 TypeInternal::Tuple(tuple) => Ok(AnalysedTypeWithUnit::analysed_type(
156 AnalysedType::Tuple(TypeTuple {
157 items: tuple
158 .iter()
159 .map(|t| t.try_into())
160 .collect::<Result<Vec<AnalysedType>, String>>()?,
161 }),
162 )),
163 TypeInternal::Record(record) => Ok(AnalysedTypeWithUnit::analysed_type(
164 AnalysedType::Record(TypeRecord {
165 fields: record
166 .iter()
167 .map(|(name, typ)| {
168 Ok(NameTypePair {
169 name: name.to_string(),
170 typ: typ.try_into()?,
171 })
172 })
173 .collect::<Result<Vec<NameTypePair>, String>>()?,
174 }),
175 )),
176 TypeInternal::Flags(flags) => Ok(AnalysedTypeWithUnit::analysed_type(
177 AnalysedType::Flags(TypeFlags {
178 names: flags.clone(),
179 }),
180 )),
181 TypeInternal::Enum(enums) => Ok(AnalysedTypeWithUnit::analysed_type(
182 AnalysedType::Enum(TypeEnum {
183 cases: enums.clone(),
184 }),
185 )),
186 TypeInternal::Option(option) => Ok(AnalysedTypeWithUnit::analysed_type(
187 AnalysedType::Option(TypeOption {
188 inner: Box::new(option.try_into()?),
189 }),
190 )),
191 TypeInternal::Result { ok, error } => Ok(AnalysedTypeWithUnit::analysed_type(
192 AnalysedType::Result(TypeResult {
194 ok: ok.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
195 err: error.as_ref().and_then(|t| t.try_into().ok().map(Box::new)),
196 }),
197 )),
198 TypeInternal::Variant(variant) => Ok(AnalysedTypeWithUnit::analysed_type(
199 AnalysedType::Variant(TypeVariant {
200 cases: variant
201 .iter()
202 .map(|(name, typ)| {
203 Ok(NameOptionTypePair {
204 name: name.clone(),
205 typ: typ.as_ref().map(|t| t.try_into()).transpose()?,
206 })
207 })
208 .collect::<Result<Vec<NameOptionTypePair>, String>>()?,
209 }),
210 )),
211 TypeInternal::Resource {
212 resource_id,
213 resource_mode,
214 } => Ok(AnalysedTypeWithUnit::analysed_type(AnalysedType::Handle(
215 TypeHandle {
216 resource_id: AnalysedResourceId(*resource_id),
217 mode: if resource_mode == &0 {
218 AnalysedResourceMode::Owned
219 } else {
220 AnalysedResourceMode::Borrowed
221 },
222 },
223 ))),
224
225 TypeInternal::AllOf(types) => Err(format!(
226 "ambiguous types {}",
227 types
228 .iter()
229 .map(|x| x.get_type_hint().to_string())
230 .collect::<Vec<_>>()
231 .join(", ")
232 )),
233 TypeInternal::Unknown => Err("failed to infer type".to_string()),
234 TypeInternal::Sequence(vec) => {
237 if vec.is_empty() {
238 Ok(AnalysedTypeWithUnit::unit())
239 } else if vec.len() == 1 {
240 let first = &vec[0];
241 Ok(first.try_into()?)
242 } else {
243 Err("function with multiple return types not supported".to_string())
244 }
245 }
246 }
247 }
248}