rib/inferred_type/
mod.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub(crate) use flatten::*;
16mod flatten;
17mod unification;
18use crate::instance_type::InstanceType;
19use crate::type_inference::kind::GetTypeKind;
20use crate::TypeName;
21use bigdecimal::num_bigint::Sign;
22use bigdecimal::BigDecimal;
23use golem_wasm_ast::analysis::analysed_type::*;
24use golem_wasm_ast::analysis::*;
25use std::collections::HashSet;
26use std::fmt::{Display, Formatter};
27use std::hash::{Hash, Hasher};
28
29#[derive(Debug, Clone, Ord, PartialOrd)]
30pub enum InferredType {
31    Bool,
32    S8,
33    U8,
34    S16,
35    U16,
36    S32,
37    U32,
38    S64,
39    U64,
40    F32,
41    F64,
42    Chr,
43    Str,
44    List(Box<InferredType>),
45    Tuple(Vec<InferredType>),
46    Record(Vec<(String, InferredType)>),
47    Flags(Vec<String>),
48    Enum(Vec<String>),
49    Option(Box<InferredType>),
50    Result {
51        ok: Option<Box<InferredType>>,
52        error: Option<Box<InferredType>>,
53    },
54    Variant(Vec<(String, Option<InferredType>)>),
55    Resource {
56        resource_id: u64,
57        resource_mode: u8,
58    },
59    Range {
60        from: Box<InferredType>,
61        to: Option<Box<InferredType>>,
62    },
63    Instance {
64        instance_type: Box<InstanceType>,
65    },
66    OneOf(Vec<InferredType>),
67    AllOf(Vec<InferredType>),
68    Unknown,
69    // Because function result can be a vector of types
70    Sequence(Vec<InferredType>),
71}
72
73impl Eq for InferredType {}
74
75impl Hash for InferredType {
76    fn hash<H: Hasher>(&self, state: &mut H) {
77        match self {
78            InferredType::Bool => 0.hash(state),
79            InferredType::S8 => 1.hash(state),
80            InferredType::U8 => 2.hash(state),
81            InferredType::S16 => 3.hash(state),
82            InferredType::U16 => 4.hash(state),
83            InferredType::S32 => 5.hash(state),
84            InferredType::U32 => 6.hash(state),
85            InferredType::S64 => 7.hash(state),
86            InferredType::U64 => 8.hash(state),
87            InferredType::F32 => 9.hash(state),
88            InferredType::F64 => 10.hash(state),
89            InferredType::Chr => 11.hash(state),
90            InferredType::Str => 12.hash(state),
91            InferredType::List(inner) => {
92                13.hash(state);
93                inner.hash(state);
94            }
95            InferredType::Tuple(inner) => {
96                14.hash(state);
97                inner.hash(state);
98            }
99            InferredType::Record(fields) => {
100                15.hash(state);
101                let mut sorted_fields = fields.clone();
102                sorted_fields.sort_by(|a, b| a.0.cmp(&b.0));
103                sorted_fields.hash(state);
104            }
105            InferredType::Flags(flags) => {
106                16.hash(state);
107                let mut sorted_flags = flags.clone();
108                sorted_flags.sort();
109                sorted_flags.hash(state);
110            }
111            InferredType::Enum(variants) => {
112                17.hash(state);
113                let mut sorted_variants = variants.clone();
114                sorted_variants.sort();
115                sorted_variants.hash(state);
116            }
117            InferredType::Option(inner) => {
118                18.hash(state);
119                inner.hash(state);
120            }
121            InferredType::Result { ok, error } => {
122                19.hash(state);
123                ok.hash(state);
124                error.hash(state);
125            }
126            InferredType::Variant(fields) => {
127                20.hash(state);
128                let mut sorted_fields = fields.clone();
129                sorted_fields.sort_by(|a, b| a.0.cmp(&b.0));
130                sorted_fields.hash(state);
131            }
132            InferredType::Resource {
133                resource_id,
134                resource_mode,
135            } => {
136                21.hash(state);
137                resource_id.hash(state);
138                resource_mode.hash(state);
139            }
140            InferredType::Range { from, to } => {
141                22.hash(state);
142                from.hash(state);
143                to.hash(state);
144            }
145            InferredType::Instance { instance_type } => {
146                23.hash(state);
147                instance_type.hash(state);
148            }
149            InferredType::OneOf(types)
150            | InferredType::AllOf(types)
151            | InferredType::Sequence(types) => {
152                24.hash(state);
153                let mut sorted_types = types.clone();
154                sorted_types.sort();
155                sorted_types.hash(state);
156            }
157            InferredType::Unknown => 25.hash(state),
158        }
159    }
160}
161
162impl PartialEq for InferredType {
163    fn eq(&self, other: &Self) -> bool {
164        match (self, other) {
165            (InferredType::Bool, InferredType::Bool) => true,
166            (InferredType::S8, InferredType::S8) => true,
167            (InferredType::U8, InferredType::U8) => true,
168            (InferredType::S16, InferredType::S16) => true,
169            (InferredType::U16, InferredType::U16) => true,
170            (InferredType::S32, InferredType::S32) => true,
171            (InferredType::U32, InferredType::U32) => true,
172            (InferredType::S64, InferredType::S64) => true,
173            (InferredType::U64, InferredType::U64) => true,
174            (InferredType::F32, InferredType::F32) => true,
175            (InferredType::F64, InferredType::F64) => true,
176            (InferredType::Chr, InferredType::Chr) => true,
177            (InferredType::Str, InferredType::Str) => true,
178            (InferredType::List(t1), InferredType::List(t2)) => t1 == t2,
179            (InferredType::Tuple(ts1), InferredType::Tuple(ts2)) => ts1 == ts2,
180            (InferredType::Record(fs1), InferredType::Record(fs2)) => fs1 == fs2,
181            (InferredType::Flags(vs1), InferredType::Flags(vs2)) => vs1 == vs2,
182            (InferredType::Enum(vs1), InferredType::Enum(vs2)) => vs1 == vs2,
183            (InferredType::Option(t1), InferredType::Option(t2)) => t1 == t2,
184            (
185                InferredType::Result {
186                    ok: ok1,
187                    error: error1,
188                },
189                InferredType::Result {
190                    ok: ok2,
191                    error: error2,
192                },
193            ) => ok1 == ok2 && error1 == error2,
194            (InferredType::Variant(vs1), InferredType::Variant(vs2)) => vs1 == vs2,
195            (
196                InferredType::Resource {
197                    resource_id: id1,
198                    resource_mode: mode1,
199                },
200                InferredType::Resource {
201                    resource_id: id2,
202                    resource_mode: mode2,
203                },
204            ) => id1 == id2 && mode1 == mode2,
205            (
206                InferredType::Range {
207                    from: from1,
208                    to: to1,
209                },
210                InferredType::Range {
211                    from: from2,
212                    to: to2,
213                },
214            ) => from1 == from2 && to1 == to2,
215            (
216                InferredType::Instance { instance_type: t1 },
217                InferredType::Instance { instance_type: t2 },
218            ) => t1 == t2,
219            (InferredType::Unknown, InferredType::Unknown) => true,
220
221            // **Fix: Sort & Compare for OneOf, AllOf, Sequence**
222            (InferredType::OneOf(ts1), InferredType::OneOf(ts2)) => {
223                let mut ts1_sorted = ts1.clone();
224                let mut ts2_sorted = ts2.clone();
225                ts1_sorted.sort();
226                ts2_sorted.sort();
227                ts1_sorted == ts2_sorted
228            }
229            (InferredType::AllOf(ts1), InferredType::AllOf(ts2)) => {
230                let mut ts1_sorted = ts1.clone();
231                let mut ts2_sorted = ts2.clone();
232                ts1_sorted.sort();
233                ts2_sorted.sort();
234                ts1_sorted == ts2_sorted
235            }
236            (InferredType::Sequence(ts1), InferredType::Sequence(ts2)) => {
237                let mut ts1_sorted = ts1.clone();
238                let mut ts2_sorted = ts2.clone();
239                ts1_sorted.sort();
240                ts2_sorted.sort();
241                ts1_sorted == ts2_sorted
242            }
243
244            _ => false,
245        }
246    }
247}
248
249#[derive(PartialEq, Clone, Debug)]
250pub enum InferredNumber {
251    S8,
252    U8,
253    S16,
254    U16,
255    S32,
256    U32,
257    S64,
258    U64,
259    F32,
260    F64,
261}
262
263impl From<InferredNumber> for InferredType {
264    fn from(inferred_number: InferredNumber) -> Self {
265        match inferred_number {
266            InferredNumber::S8 => InferredType::S8,
267            InferredNumber::U8 => InferredType::U8,
268            InferredNumber::S16 => InferredType::S16,
269            InferredNumber::U16 => InferredType::U16,
270            InferredNumber::S32 => InferredType::S32,
271            InferredNumber::U32 => InferredType::U32,
272            InferredNumber::S64 => InferredType::S64,
273            InferredNumber::U64 => InferredType::U64,
274            InferredNumber::F32 => InferredType::F32,
275            InferredNumber::F64 => InferredType::F64,
276        }
277    }
278}
279
280impl From<&BigDecimal> for InferredType {
281    fn from(value: &BigDecimal) -> Self {
282        let sign = value.sign();
283
284        if value.fractional_digit_count() <= 0 {
285            match sign {
286                Sign::NoSign => InferredType::U64,
287                Sign::Minus => InferredType::S64,
288                Sign::Plus => InferredType::U64,
289            }
290        } else {
291            InferredType::F64
292        }
293    }
294}
295
296#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
297pub struct RangeType {
298    from: Box<InferredType>,
299    to: Option<Box<InferredType>>,
300}
301
302impl Display for InferredNumber {
303    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
304        let type_name = TypeName::from(self);
305        write!(f, "{}", type_name)
306    }
307}
308
309impl InferredType {
310    pub fn printable(&self) -> String {
311        // Try a fully blown type name or if it fails,
312        // get the `kind` of inferred type
313        TypeName::try_from(self.clone())
314            .map(|tn| tn.to_string())
315            .unwrap_or(self.get_type_kind().to_string())
316    }
317
318    pub fn contains_only_number(&self) -> bool {
319        match self {
320            InferredType::S8
321            | InferredType::U8
322            | InferredType::S16
323            | InferredType::U16
324            | InferredType::S32
325            | InferredType::U32
326            | InferredType::S64
327            | InferredType::U64
328            | InferredType::F32
329            | InferredType::F64 => true,
330            InferredType::AllOf(types) => types.iter().all(|t| t.contains_only_number()),
331            InferredType::OneOf(types) => types.iter().all(|t| t.contains_only_number()),
332            InferredType::Bool => false,
333            InferredType::Chr => false,
334            InferredType::Str => false,
335            InferredType::List(_) => false,
336            InferredType::Tuple(_) => false,
337            InferredType::Record(_) => false,
338            InferredType::Flags(_) => false,
339            InferredType::Enum(_) => false,
340            InferredType::Option(_) => false,
341            InferredType::Result { .. } => false,
342            InferredType::Variant(_) => false,
343            InferredType::Resource { .. } => false,
344            InferredType::Range { .. } => false,
345            InferredType::Instance { .. } => false,
346            InferredType::Unknown => false,
347            InferredType::Sequence(_) => false,
348        }
349    }
350
351    pub fn as_number(&self) -> Result<InferredNumber, String> {
352        fn go(inferred_type: &InferredType, found: &mut Vec<InferredNumber>) -> Result<(), String> {
353            match inferred_type {
354                InferredType::S8 => {
355                    found.push(InferredNumber::S8);
356                    Ok(())
357                }
358                InferredType::U8 => {
359                    found.push(InferredNumber::U8);
360                    Ok(())
361                }
362                InferredType::S16 => {
363                    found.push(InferredNumber::S16);
364                    Ok(())
365                }
366                InferredType::U16 => {
367                    found.push(InferredNumber::U16);
368                    Ok(())
369                }
370                InferredType::S32 => {
371                    found.push(InferredNumber::U16);
372                    Ok(())
373                }
374                InferredType::U32 => {
375                    found.push(InferredNumber::U32);
376                    Ok(())
377                }
378                InferredType::S64 => {
379                    found.push(InferredNumber::S64);
380                    Ok(())
381                }
382                InferredType::U64 => {
383                    found.push(InferredNumber::U64);
384                    Ok(())
385                }
386                InferredType::F32 => {
387                    found.push(InferredNumber::F32);
388                    Ok(())
389                }
390                InferredType::F64 => {
391                    found.push(InferredNumber::F64);
392                    Ok(())
393                }
394                InferredType::AllOf(all_variables) => {
395                    let mut previous: Option<InferredNumber> = None;
396                    for variable in all_variables {
397                        go(variable, found)?;
398
399                        if let Some(current) = found.first() {
400                            match &previous {
401                                None => {
402                                    previous = Some(current.clone());
403                                    found.push(current.clone());
404                                }
405                                Some(previous) => {
406                                    if previous != current {
407                                        return Err(format!(
408                                            "expected the same type of number. But found {}, {}",
409                                            current, previous
410                                        ));
411                                    }
412
413                                    found.push(current.clone());
414                                }
415                            }
416                        } else {
417                            return Err("failed to get a number".to_string());
418                        }
419                    }
420
421                    Ok(())
422                }
423                InferredType::Range { .. } => Err("used as range".to_string()),
424                InferredType::Bool => Err(format!("used as {}", "bool")),
425                InferredType::Chr => Err(format!("used as {}", "char")),
426                InferredType::Str => Err(format!("used as {}", "string")),
427                InferredType::List(_) => Err(format!("used as {}", "list")),
428                InferredType::Tuple(_) => Err(format!("used as {}", "tuple")),
429                InferredType::Record(_) => Err(format!("used as {}", "record")),
430                InferredType::Flags(_) => Err(format!("used as {}", "flags")),
431                InferredType::Enum(_) => Err(format!("used as {}", "enum")),
432                InferredType::Option(_) => Err(format!("used as {}", "option")),
433                InferredType::Result { .. } => Err(format!("used as {}", "result")),
434                InferredType::Variant(_) => Err(format!("used as {}", "variant")),
435
436                // It's ok to have one-of as far as there is a precise number already `found`
437                InferredType::OneOf(_) => {
438                    if found.is_empty() {
439                        Err("not a number.".to_string())
440                    } else {
441                        Ok(())
442                    }
443                }
444                InferredType::Unknown => Err("found unknown".to_string()),
445
446                InferredType::Sequence(_) => {
447                    Err(format!("used as {}", "function-multi-parameter-return"))
448                }
449                InferredType::Resource { .. } => Err(format!("used as {}", "resource")),
450                InferredType::Instance { .. } => Err(format!("used as {}", "instance")),
451            }
452        }
453
454        let mut found: Vec<InferredNumber> = vec![];
455        go(self, &mut found)?;
456        found.first().cloned().ok_or("Failed".to_string())
457    }
458
459    pub fn number() -> InferredType {
460        InferredType::OneOf(vec![
461            InferredType::U64,
462            InferredType::U32,
463            InferredType::U8,
464            InferredType::U16,
465            InferredType::S64,
466            InferredType::S32,
467            InferredType::S8,
468            InferredType::S16,
469            InferredType::F64,
470            InferredType::F32,
471        ])
472    }
473
474    pub fn un_resolved(&self) -> bool {
475        self.is_unknown() || self.is_one_of()
476    }
477
478    pub fn all_of(types: Vec<InferredType>) -> Option<InferredType> {
479        let flattened = InferredType::flatten_all_of_inferred_types(&types);
480
481        let mut types: Vec<InferredType> =
482            flattened.into_iter().filter(|t| !t.is_unknown()).collect();
483
484        let mut unique_types: HashSet<InferredType> = HashSet::new();
485        types.retain(|t| unique_types.insert(t.clone()));
486
487        if unique_types.is_empty() {
488            None
489        } else if unique_types.len() == 1 {
490            unique_types.into_iter().next()
491        } else {
492            let mut unique_all_of_types: Vec<InferredType> = unique_types.into_iter().collect();
493            unique_all_of_types.sort();
494            Some(InferredType::AllOf(unique_all_of_types))
495        }
496    }
497
498    pub fn one_of(types: Vec<InferredType>) -> Option<InferredType> {
499        let flattened = InferredType::flatten_one_of_inferred_types(&types);
500
501        let mut types: Vec<InferredType> =
502            flattened.into_iter().filter(|t| !t.is_unknown()).collect();
503
504        // Make sure they are unique types
505        let mut unique_types: HashSet<InferredType> = HashSet::new();
506        types.retain(|t| unique_types.insert(t.clone()));
507
508        if types.is_empty() {
509            None
510        } else if types.len() == 1 {
511            types.into_iter().next()
512        } else {
513            let mut unique_one_of_types: Vec<InferredType> = unique_types.into_iter().collect();
514            unique_one_of_types.sort();
515            Some(InferredType::OneOf(unique_one_of_types))
516        }
517    }
518
519    pub fn is_unit(&self) -> bool {
520        match self {
521            InferredType::Sequence(types) => types.is_empty(),
522            _ => false,
523        }
524    }
525    pub fn is_unknown(&self) -> bool {
526        matches!(self, InferredType::Unknown)
527    }
528
529    pub fn is_one_of(&self) -> bool {
530        matches!(self, InferredType::OneOf(_))
531    }
532
533    pub fn is_valid_wit_type(&self) -> bool {
534        AnalysedType::try_from(self.clone()).is_ok()
535    }
536
537    pub fn is_all_of(&self) -> bool {
538        matches!(self, InferredType::AllOf(_))
539    }
540
541    pub fn is_number(&self) -> bool {
542        matches!(
543            self,
544            InferredType::S8
545                | InferredType::U8
546                | InferredType::S16
547                | InferredType::U16
548                | InferredType::S32
549                | InferredType::U32
550                | InferredType::S64
551                | InferredType::U64
552                | InferredType::F32
553                | InferredType::F64
554        )
555    }
556
557    pub fn is_string(&self) -> bool {
558        matches!(self, InferredType::Str)
559    }
560
561    pub fn flatten_all_of_inferred_types(types: &Vec<InferredType>) -> Vec<InferredType> {
562        flatten_all_of_list(types)
563    }
564
565    pub fn flatten_one_of_inferred_types(types: &Vec<InferredType>) -> Vec<InferredType> {
566        flatten_one_of_list(types)
567    }
568
569    // Here unification returns an inferred type, but it doesn't necessarily imply
570    // its valid type, which can be converted to a wasm type.
571    pub fn try_unify(&self) -> Result<InferredType, String> {
572        unification::try_unify_type(self)
573    }
574
575    pub fn unify(&self) -> Result<InferredType, String> {
576        unification::unify(self).map(|unified| unified.inferred_type())
577    }
578
579    pub fn unify_all_alternative_types(types: &Vec<InferredType>) -> InferredType {
580        unification::unify_all_alternative_types(types)
581    }
582
583    pub fn unify_all_required_types(types: &Vec<InferredType>) -> Result<InferredType, String> {
584        unification::unify_all_required_types(types)
585    }
586
587    // Unify types where both types do matter. Example in reality x can form to be both U64 and U32 in the IR, resulting in AllOf
588    // Result of this type hardly becomes OneOf
589    pub fn unify_with_required(&self, other: &InferredType) -> Result<InferredType, String> {
590        unification::unify_with_required(self, other)
591    }
592
593    pub fn unify_with_alternative(&self, other: &InferredType) -> Result<InferredType, String> {
594        unification::unify_with_alternative(self, other)
595    }
596
597    // There is only one way to merge types. If they are different, they are merged into AllOf
598    pub fn merge(&self, new_inferred_type: InferredType) -> InferredType {
599        if !internal::need_update(self, &new_inferred_type) {
600            return self.clone();
601        }
602
603        match (self, new_inferred_type) {
604            (InferredType::Unknown, new_type) => new_type,
605
606            (InferredType::AllOf(existing_types), InferredType::AllOf(new_types)) => {
607                let mut all_types = new_types.clone();
608                all_types.extend(existing_types.clone());
609
610                InferredType::all_of(all_types).unwrap_or(InferredType::Unknown)
611            }
612
613            (InferredType::AllOf(existing_types), new_type) => {
614                let mut all_types = existing_types.clone();
615                all_types.push(new_type);
616
617                InferredType::all_of(all_types).unwrap_or(InferredType::Unknown)
618            }
619
620            (current_type, InferredType::AllOf(new_types)) => {
621                let mut all_types = new_types.clone();
622                all_types.push(current_type.clone());
623
624                InferredType::all_of(all_types).unwrap_or(InferredType::Unknown)
625            }
626
627            (InferredType::OneOf(existing_types), InferredType::OneOf(new_types)) => {
628                let mut one_of_types = new_types.clone();
629                if &new_types == existing_types {
630                    return InferredType::OneOf(one_of_types);
631                } else {
632                    one_of_types.extend(existing_types.clone());
633                }
634
635                InferredType::one_of(one_of_types).unwrap_or(InferredType::Unknown)
636            }
637
638            (InferredType::OneOf(existing_types), new_type) => {
639                if existing_types.contains(&new_type) {
640                    new_type
641                } else {
642                    InferredType::all_of(vec![self.clone(), new_type])
643                        .unwrap_or(InferredType::Unknown)
644                }
645            }
646
647            (current_type, InferredType::OneOf(newtypes)) => {
648                if newtypes.contains(current_type) {
649                    current_type.clone()
650                } else {
651                    InferredType::all_of(vec![current_type.clone(), InferredType::OneOf(newtypes)])
652                        .unwrap_or(InferredType::Unknown)
653                }
654            }
655
656            (current_type, new_type) => {
657                InferredType::all_of(vec![current_type.clone(), new_type.clone()])
658                    .unwrap_or(InferredType::Unknown)
659            }
660        }
661    }
662
663    pub fn from_variant_cases(type_variant: &TypeVariant) -> InferredType {
664        let cases = type_variant
665            .cases
666            .iter()
667            .map(|name_type_pair| {
668                (
669                    name_type_pair.name.clone(),
670                    name_type_pair.typ.clone().map(|t| t.into()),
671                )
672            })
673            .collect();
674
675        InferredType::Variant(cases)
676    }
677
678    pub fn from_enum_cases(type_enum: &TypeEnum) -> InferredType {
679        InferredType::Enum(type_enum.cases.clone())
680    }
681}
682
683impl TryFrom<InferredType> for AnalysedType {
684    type Error = String;
685
686    fn try_from(value: InferredType) -> Result<Self, Self::Error> {
687        match value {
688            InferredType::Bool => Ok(bool()),
689            InferredType::S8 => Ok(s8()),
690            InferredType::U8 => Ok(u8()),
691            InferredType::S16 => Ok(s16()),
692            InferredType::U16 => Ok(u16()),
693            InferredType::S32 => Ok(s32()),
694            InferredType::U32 => Ok(u32()),
695            InferredType::S64 => Ok(s64()),
696            InferredType::U64 => Ok(u64()),
697            InferredType::F32 => Ok(f32()),
698            InferredType::F64 => Ok(f64()),
699            InferredType::Chr => Ok(chr()),
700            InferredType::Str => Ok(str()),
701            InferredType::List(typ) => {
702                let typ: AnalysedType = (*typ).try_into()?;
703                Ok(list(typ))
704            }
705            InferredType::Tuple(types) => {
706                let types: Vec<AnalysedType> = types
707                    .into_iter()
708                    .map(|t| t.try_into())
709                    .collect::<Result<Vec<AnalysedType>, _>>()?;
710                Ok(tuple(types))
711            }
712            InferredType::Record(field_and_types) => {
713                let mut field_pairs: Vec<NameTypePair> = vec![];
714                for (name, typ) in field_and_types {
715                    let typ: AnalysedType = typ.try_into()?;
716                    field_pairs.push(NameTypePair { name, typ });
717                }
718                Ok(record(field_pairs))
719            }
720            InferredType::Flags(names) => Ok(AnalysedType::Flags(TypeFlags { names })),
721            InferredType::Enum(cases) => Ok(AnalysedType::Enum(TypeEnum { cases })),
722            InferredType::Option(typ) => {
723                let typ: AnalysedType = (*typ).try_into()?;
724                Ok(option(typ))
725            }
726            InferredType::Result { ok, error } => {
727                let ok_option: Option<AnalysedType> = ok.map(|t| (*t).try_into()).transpose()?;
728                let ok = ok_option.ok_or("Expected ok type in result".to_string())?;
729                let error_option: Option<AnalysedType> =
730                    error.map(|t| (*t).try_into()).transpose()?;
731                let error = error_option.ok_or("Expected error type in result".to_string())?;
732                Ok(result(ok, error))
733            }
734            InferredType::Variant(name_and_optiona_inferred_types) => {
735                let mut cases: Vec<NameOptionTypePair> = vec![];
736                for (name, typ) in name_and_optiona_inferred_types {
737                    let typ: Option<AnalysedType> = typ.map(|t| t.try_into()).transpose()?;
738                    cases.push(NameOptionTypePair { name, typ });
739                }
740                Ok(variant(cases))
741            }
742            InferredType::Resource {
743                resource_id,
744                resource_mode,
745            } => Ok(handle(
746                AnalysedResourceId(resource_id),
747                match resource_mode {
748                    0 => AnalysedResourceMode::Owned,
749                    1 => AnalysedResourceMode::Borrowed,
750                    _ => return Err("Invalid resource mode".to_string()),
751                },
752            )),
753            InferredType::Instance { .. } => {
754                Err("Cannot convert instance type to analysed type".to_string())
755            }
756            InferredType::OneOf(_) => {
757                Err("Cannot convert one of type to analysed type".to_string())
758            }
759            InferredType::AllOf(_) => {
760                Err("Cannot convert all of type to analysed type".to_string())
761            }
762            InferredType::Unknown => {
763                Err("Cannot convert unknown type to analysed type".to_string())
764            }
765            InferredType::Sequence(_) => {
766                Err("Cannot convert function return sequence type to analysed type".to_string())
767            }
768            InferredType::Range { from, to } => {
769                let from: AnalysedType = (*from).try_into()?;
770                let to: Option<AnalysedType> = to.map(|t| (*t).try_into()).transpose()?;
771                let analysed_type = match (from, to) {
772                    (from_type, Some(to_type)) => record(vec![
773                        field("from", option(from_type)),
774                        field("to", option(to_type)),
775                        field("inclusive", bool()),
776                    ]),
777
778                    (from_type, None) => record(vec![
779                        field("from", option(from_type)),
780                        field("inclusive", bool()),
781                    ]),
782                };
783                Ok(analysed_type)
784            }
785        }
786    }
787}
788
789impl From<AnalysedType> for InferredType {
790    fn from(analysed_type: AnalysedType) -> Self {
791        match analysed_type {
792            AnalysedType::Bool(_) => InferredType::Bool,
793            AnalysedType::S8(_) => InferredType::S8,
794            AnalysedType::U8(_) => InferredType::U8,
795            AnalysedType::S16(_) => InferredType::S16,
796            AnalysedType::U16(_) => InferredType::U16,
797            AnalysedType::S32(_) => InferredType::S32,
798            AnalysedType::U32(_) => InferredType::U32,
799            AnalysedType::S64(_) => InferredType::S64,
800            AnalysedType::U64(_) => InferredType::U64,
801            AnalysedType::F32(_) => InferredType::F32,
802            AnalysedType::F64(_) => InferredType::F64,
803            AnalysedType::Chr(_) => InferredType::Chr,
804            AnalysedType::Str(_) => InferredType::Str,
805            AnalysedType::List(t) => InferredType::List(Box::new((*t.inner).into())),
806            AnalysedType::Tuple(ts) => {
807                InferredType::Tuple(ts.items.into_iter().map(|t| t.into()).collect())
808            }
809            AnalysedType::Record(fs) => InferredType::Record(
810                fs.fields
811                    .into_iter()
812                    .map(|name_type| (name_type.name, name_type.typ.into()))
813                    .collect(),
814            ),
815            AnalysedType::Flags(vs) => InferredType::Flags(vs.names),
816            AnalysedType::Enum(vs) => InferredType::from_enum_cases(&vs),
817            AnalysedType::Option(t) => InferredType::Option(Box::new((*t.inner).into())),
818            AnalysedType::Result(golem_wasm_ast::analysis::TypeResult { ok, err, .. }) => {
819                InferredType::Result {
820                    ok: ok.map(|t| Box::new((*t).into())),
821                    error: err.map(|t| Box::new((*t).into())),
822                }
823            }
824            AnalysedType::Variant(vs) => InferredType::from_variant_cases(&vs),
825            AnalysedType::Handle(golem_wasm_ast::analysis::TypeHandle { resource_id, mode }) => {
826                InferredType::Resource {
827                    resource_id: resource_id.0,
828                    resource_mode: match mode {
829                        AnalysedResourceMode::Owned => 0,
830                        AnalysedResourceMode::Borrowed => 1,
831                    },
832                }
833            }
834        }
835    }
836}
837
838mod internal {
839    use crate::InferredType;
840
841    pub(crate) fn need_update(
842        current_inferred_type: &InferredType,
843        new_inferred_type: &InferredType,
844    ) -> bool {
845        current_inferred_type != new_inferred_type && !new_inferred_type.is_unknown()
846    }
847}
848
849#[cfg(test)]
850mod test {
851
852    #[test]
853    fn test_flatten_one_of() {
854        use super::InferredType;
855        let one_of = vec![
856            InferredType::U8,
857            InferredType::U16,
858            InferredType::U32,
859            InferredType::OneOf(vec![
860                InferredType::U8,
861                InferredType::U16,
862                InferredType::U32,
863                InferredType::AllOf(vec![
864                    InferredType::U64,
865                    InferredType::OneOf(vec![InferredType::U64, InferredType::U8]),
866                ]),
867            ]),
868        ];
869
870        let flattened = InferredType::flatten_one_of_inferred_types(&one_of);
871
872        let expected = vec![
873            InferredType::U8,
874            InferredType::U16,
875            InferredType::U32,
876            InferredType::U8,
877            InferredType::U16,
878            InferredType::U32,
879            InferredType::AllOf(vec![
880                InferredType::U64,
881                InferredType::OneOf(vec![InferredType::U64, InferredType::U8]),
882            ]),
883        ];
884
885        assert_eq!(flattened, expected)
886    }
887}