wac_types/
aggregator.rs

1use crate::{
2    DefinedType, DefinedTypeId, FuncType, FuncTypeId, Interface, InterfaceId, ItemKind,
3    ModuleTypeId, Record, Resource, ResourceAlias, ResourceId, SubtypeChecker, Type, Types,
4    UsedType, ValueType, Variant, World, WorldId,
5};
6use anyhow::{bail, Context, Result};
7use indexmap::IndexMap;
8use std::collections::HashMap;
9
10/// Used to aggregate types defined in different `Types` collections.
11///
12/// A type aggregator can be used to merge compatible definitions of
13/// the same type into a single supertype definition stored within the
14/// aggregator; this is useful for imports that are shared across
15/// different instantiation arguments.
16///
17/// It works by first recursively remapping a type from a foreign `Types`
18/// collection into its own `Types` collection; any further attempt
19/// to aggregate the type causes a merge of type definitions provided
20/// they are compatible.
21#[derive(Default, Debug)]
22pub struct TypeAggregator {
23    /// The aggregated types collection.
24    types: Types,
25    /// The map from import name to aggregated item kind.
26    imports: IndexMap<String, ItemKind>,
27    /// A map from foreign type to remapped local type.
28    remapped: HashMap<Type, Type>,
29    /// A map of interface names to remapped interface id.
30    interfaces: HashMap<String, InterfaceId>,
31}
32
33impl TypeAggregator {
34    /// Creates a new type aggregator.
35    pub fn new() -> Self {
36        Self::default()
37    }
38
39    /// Gets the aggregator's type collection.
40    pub fn types(&self) -> &Types {
41        &self.types
42    }
43
44    /// Iterates the imported types in the aggregator.
45    pub fn imports(&self) -> impl Iterator<Item = (&str, ItemKind)> {
46        self.imports.iter().map(|(n, k)| (n.as_str(), *k))
47    }
48
49    /// Aggregates a item kind from a specified type collection using the given
50    /// import name.
51    ///
52    /// Note that if the aggregate operation fails, the aggregator is consumed.
53    pub fn aggregate(
54        mut self,
55        name: &str,
56        types: &Types,
57        kind: ItemKind,
58        checker: &mut SubtypeChecker,
59    ) -> Result<Self> {
60        // First check if this import has already been remapped into our
61        // types collection.
62        // If it has already been remapped, do a merge; otherwise, remap it.
63        if let Some(existing) = self.imports.get(name).copied() {
64            self.merge_item_kind(existing, types, kind, checker)?;
65            return Ok(self);
66        }
67
68        let remapped = self.remap_item_kind(types, kind, checker)?;
69        let prev = self.imports.insert(name.to_string(), remapped);
70        assert!(prev.is_none());
71        Ok(self)
72    }
73
74    fn merge_item_kind(
75        &mut self,
76        existing: ItemKind,
77        types: &Types,
78        kind: ItemKind,
79        checker: &mut SubtypeChecker,
80    ) -> Result<()> {
81        match (existing, kind) {
82            (ItemKind::Instance(existing), ItemKind::Instance(id)) => {
83                self.merge_interface(existing, types, id, checker)
84            }
85            (ItemKind::Component(existing), ItemKind::Component(id)) => {
86                self.merge_world(existing, types, id, checker)
87            }
88            (ItemKind::Func(existing), ItemKind::Func(id)) => {
89                self.merge_func_type(existing, types, id, checker)
90            }
91            (ItemKind::Module(existing), ItemKind::Module(id)) => {
92                self.merge_module_type(existing, types, id, checker)
93            }
94            (ItemKind::Type(existing), ItemKind::Type(ty)) => {
95                self.merge_type(existing, types, ty, checker)
96            }
97            (ItemKind::Value(existing), ItemKind::Value(ty)) => {
98                self.merge_value_type(existing, types, ty, checker)
99            }
100            (existing, kind) => {
101                bail!(
102                    "{existing} cannot be merged with {kind}",
103                    existing = existing.desc(&self.types),
104                    kind = kind.desc(types)
105                );
106            }
107        }
108    }
109
110    fn merge_interface(
111        &mut self,
112        existing: InterfaceId,
113        types: &Types,
114        id: InterfaceId,
115        checker: &mut SubtypeChecker,
116    ) -> Result<()> {
117        // Merge the used types of the two interfaces
118        self.merge_interface_used_types(existing, types, id, checker)?;
119
120        // Merge the interface's exports
121        for (name, source_kind) in &types[id].exports {
122            if let Some(target_kind) = self.types[existing].exports.get(name).copied() {
123                // If the source kind is already a subtype of the target, do nothing
124                if checker
125                    .is_subtype(*source_kind, types, target_kind, &self.types)
126                    .is_ok()
127                {
128                    // Keep track that the source type should be replaced with the
129                    // target type wherever it's used.
130                    self.remapped.insert(source_kind.ty(), target_kind.ty());
131                    continue;
132                }
133
134                // Otherwise, the target *must* be a subtype of the source
135                // We'll remap the source below and replace
136                checker
137                    .is_subtype(target_kind, &self.types, *source_kind, types)
138                    .with_context(|| format!("mismatched type for export `{name}`"))?;
139            }
140
141            let remapped = self.remap_item_kind(types, *source_kind, checker)?;
142            self.types[existing].exports.insert(name.clone(), remapped);
143        }
144
145        Ok(())
146    }
147
148    fn merge_interface_used_types(
149        &mut self,
150        existing: InterfaceId,
151        types: &Types,
152        id: InterfaceId,
153        checker: &mut SubtypeChecker,
154    ) -> Result<()> {
155        let source = &types[id];
156        for (name, used) in &source.uses {
157            let used_interface = types[used.interface]
158                .id
159                .as_ref()
160                .context("used type has no interface identifier")?;
161
162            // Validate any existing used type of the same name
163            if let Some(existing) = self.types[existing].uses.get(name) {
164                let existing_interface = self.types[existing.interface]
165                    .id
166                    .as_ref()
167                    .context("used type has no interface identifier")?;
168
169                // The interface names must match
170                if existing_interface != used_interface {
171                    bail!("cannot merge used type `{name}` as it is expected to be from interface `{existing_interface}` but it is from interface `{used_interface}`");
172                }
173
174                // The types must be exported with the same name
175                if existing.name != used.name {
176                    bail!("cannot merge used type `{name}` as the export names are mismatched");
177                }
178            }
179
180            // Remap the used interface; this will handle merging if we've seen the interface before
181            let remapped = self.remap_interface(types, used.interface, checker)?;
182            match self.types[existing].uses.get(name) {
183                Some(existing) => {
184                    assert_eq!(
185                        existing.interface, remapped,
186                        "expected a merge to have occurred"
187                    );
188                }
189                None => {
190                    self.types[existing].uses.insert(
191                        name.clone(),
192                        UsedType {
193                            interface: remapped,
194                            name: used.name.clone(),
195                        },
196                    );
197                }
198            }
199        }
200
201        Ok(())
202    }
203
204    fn merge_world(
205        &mut self,
206        existing: WorldId,
207        types: &Types,
208        id: WorldId,
209        checker: &mut SubtypeChecker,
210    ) -> Result<()> {
211        // Merge the used types of the two worlds
212        self.merge_world_used_types(existing, types, id, checker)?;
213
214        // Merge the worlds's imports
215        checker.invert();
216        for (name, source_kind) in &types[id].imports {
217            if let Some(target_kind) = self.types[existing].imports.get(name).copied() {
218                // If the target kind is already a subtype of the source, do nothing
219                if checker
220                    .is_subtype(target_kind, &self.types, *source_kind, types)
221                    .is_ok()
222                {
223                    continue;
224                }
225
226                // Otherwise, the source *must* be a subtype of the target
227                // We'll remap the source below and replace
228                checker
229                    .is_subtype(*source_kind, types, target_kind, &self.types)
230                    .with_context(|| format!("mismatched type for export `{name}`"))?;
231            }
232
233            let remapped = self.remap_item_kind(types, *source_kind, checker)?;
234            self.types[existing].imports.insert(name.clone(), remapped);
235        }
236
237        checker.revert();
238
239        // Merge the worlds's exports
240        for (name, source_kind) in &types[id].exports {
241            if let Some(target_kind) = self.types[existing].exports.get(name).copied() {
242                // If the source kind is already a subtype of the target, do nothing
243                if checker
244                    .is_subtype(*source_kind, types, target_kind, &self.types)
245                    .is_ok()
246                {
247                    continue;
248                }
249
250                // Otherwise, the target *must* be a subtype of the source
251                // We'll remap the source below and replace
252                checker
253                    .is_subtype(target_kind, &self.types, *source_kind, types)
254                    .with_context(|| format!("mismatched type for export `{name}`"))?;
255            }
256
257            let remapped = self.remap_item_kind(types, *source_kind, checker)?;
258            self.types[existing].exports.insert(name.clone(), remapped);
259        }
260
261        Ok(())
262    }
263
264    fn merge_world_used_types(
265        &mut self,
266        existing: WorldId,
267        types: &Types,
268        id: WorldId,
269        checker: &mut SubtypeChecker,
270    ) -> Result<()> {
271        let source = &types[id];
272        for (name, used) in &source.uses {
273            let used_interface = types[used.interface]
274                .id
275                .as_ref()
276                .context("used type has no interface identifier")?;
277
278            // Validate any existing used type of the same name
279            if let Some(existing) = self.types[existing].uses.get(name) {
280                let existing_interface = self.types[existing.interface]
281                    .id
282                    .as_ref()
283                    .context("used type has no interface identifier")?;
284
285                // The interface names must match
286                if existing_interface != used_interface {
287                    bail!("cannot merge used type `{name}` as it is expected to be from interface `{existing_interface}` but it is from interface `{used_interface}`");
288                }
289
290                // The types must be exported with the same name
291                if existing.name != used.name {
292                    bail!("cannot merge used type `{name}` as the export names are mismatched");
293                }
294            }
295
296            // Remap the used interface; this will handle merging if we've seen the interface before
297            let remapped = self.remap_interface(types, used.interface, checker)?;
298            match self.types[existing].uses.get(name) {
299                Some(existing) => {
300                    assert_eq!(
301                        existing.interface, remapped,
302                        "expected a merge to have occurred"
303                    );
304                }
305                None => {
306                    let prev = self.types[existing].uses.insert(
307                        name.clone(),
308                        UsedType {
309                            interface: remapped,
310                            name: used.name.clone(),
311                        },
312                    );
313                    assert!(prev.is_none());
314                }
315            }
316        }
317
318        Ok(())
319    }
320
321    fn merge_func_type(
322        &mut self,
323        existing: FuncTypeId,
324        types: &Types,
325        id: FuncTypeId,
326        checker: &mut SubtypeChecker,
327    ) -> Result<()> {
328        // Currently function types are full equality for subtype checking, so
329        // simply do a subtype check in both directions
330        checker.is_subtype(
331            ItemKind::Func(id),
332            types,
333            ItemKind::Func(existing),
334            &self.types,
335        )?;
336        checker.is_subtype(
337            ItemKind::Func(existing),
338            &self.types,
339            ItemKind::Func(id),
340            types,
341        )?;
342
343        Ok(())
344    }
345
346    fn merge_module_type(
347        &mut self,
348        existing: ModuleTypeId,
349        types: &Types,
350        id: ModuleTypeId,
351        checker: &mut SubtypeChecker,
352    ) -> Result<()> {
353        // Merge the module type's imports
354        checker.invert();
355        for (name, source_extern) in &types[id].imports {
356            if let Some(target_extern) = self.types[existing].imports.get(name) {
357                // If the target extern is already a subtype of the source, do nothing
358                if checker
359                    .core_extern(target_extern, &self.types, source_extern, types)
360                    .is_ok()
361                {
362                    continue;
363                }
364
365                // Otherwise, the source *must* be a subtype of the target
366                // We'll remap the source below and replace
367                checker
368                    .core_extern(source_extern, types, target_extern, &self.types)
369                    .with_context(|| {
370                        format!(
371                            "mismatched type for import `{m}::{n}`",
372                            m = name.0,
373                            n = name.1
374                        )
375                    })?;
376            }
377
378            self.types[existing]
379                .imports
380                .insert(name.clone(), source_extern.clone());
381        }
382
383        checker.revert();
384
385        // Merge the module type's exports
386        for (name, source_extern) in &types[id].exports {
387            if let Some(target_extern) = self.types[existing].exports.get(name) {
388                // If the source kind is already a subtype of the target, do nothing
389                // If the target extern is already a subtype of the source, do nothing
390                if checker
391                    .core_extern(source_extern, types, target_extern, &self.types)
392                    .is_ok()
393                {
394                    continue;
395                }
396
397                // Otherwise, the target *must* be a subtype of the source
398                // We'll remap the source below and replace
399                checker
400                    .core_extern(target_extern, &self.types, source_extern, types)
401                    .with_context(|| format!("mismatched type for export `{name}`"))?;
402            }
403
404            self.types[existing]
405                .exports
406                .insert(name.clone(), source_extern.clone());
407        }
408
409        Ok(())
410    }
411
412    fn merge_type(
413        &mut self,
414        existing: Type,
415        types: &Types,
416        ty: Type,
417        checker: &mut SubtypeChecker,
418    ) -> Result<()> {
419        match (existing, ty) {
420            (Type::Resource(existing), Type::Resource(id)) => {
421                self.merge_resource(existing, types, id, checker)
422            }
423            (Type::Func(existing), Type::Func(id)) => {
424                self.merge_func_type(existing, types, id, checker)
425            }
426            (Type::Value(existing), Type::Value(ty)) => {
427                self.merge_value_type(existing, types, ty, checker)
428            }
429            (Type::Interface(existing), Type::Interface(id)) => {
430                self.merge_interface(existing, types, id, checker)
431            }
432            (Type::World(existing), Type::World(id)) => {
433                self.merge_world(existing, types, id, checker)
434            }
435            (Type::Module(existing), Type::Module(id)) => {
436                self.merge_module_type(existing, types, id, checker)
437            }
438            _ => bail!(
439                "{existing} cannot be merged with {ty}",
440                existing = existing.desc(&self.types),
441                ty = ty.desc(types)
442            ),
443        }
444    }
445
446    fn merge_resource(
447        &mut self,
448        existing: ResourceId,
449        types: &Types,
450        id: ResourceId,
451        checker: &mut SubtypeChecker,
452    ) -> Result<()> {
453        // Currently the subtype check is only checking that the underlying
454        // resource names are the same; check for equality
455        checker.is_subtype(
456            ItemKind::Type(Type::Resource(id)),
457            types,
458            ItemKind::Type(Type::Resource(existing)),
459            &self.types,
460        )?;
461
462        checker.is_subtype(
463            ItemKind::Type(Type::Resource(existing)),
464            &self.types,
465            ItemKind::Type(Type::Resource(id)),
466            types,
467        )?;
468
469        Ok(())
470    }
471
472    fn merge_value_type(
473        &mut self,
474        existing: ValueType,
475        types: &Types,
476        ty: ValueType,
477        checker: &mut SubtypeChecker,
478    ) -> Result<()> {
479        // Currently the subtype check for value types is done by equality
480        checker.is_subtype(
481            ItemKind::Value(ty),
482            types,
483            ItemKind::Value(existing),
484            &self.types,
485        )?;
486
487        checker.is_subtype(
488            ItemKind::Value(existing),
489            &self.types,
490            ItemKind::Value(ty),
491            types,
492        )?;
493
494        Ok(())
495    }
496
497    fn remap_item_kind(
498        &mut self,
499        types: &Types,
500        kind: ItemKind,
501        checker: &mut SubtypeChecker,
502    ) -> Result<ItemKind> {
503        match kind {
504            ItemKind::Type(ty) => Ok(ItemKind::Type(self.remap_type(types, ty, checker)?)),
505            ItemKind::Func(id) => Ok(ItemKind::Func(self.remap_func_type(types, id, checker)?)),
506            ItemKind::Instance(id) => Ok(ItemKind::Instance(
507                self.remap_interface(types, id, checker)?,
508            )),
509            ItemKind::Component(id) => {
510                Ok(ItemKind::Component(self.remap_world(types, id, checker)?))
511            }
512            ItemKind::Module(id) => Ok(ItemKind::Module(self.remap_module_type(types, id))),
513            ItemKind::Value(ty) => Ok(ItemKind::Value(self.remap_value_type(types, ty, checker)?)),
514        }
515    }
516
517    fn remap_type(
518        &mut self,
519        types: &Types,
520        ty: Type,
521        checker: &mut SubtypeChecker,
522    ) -> Result<Type> {
523        match ty {
524            Type::Resource(id) => Ok(Type::Resource(self.remap_resource(types, id, checker)?)),
525            Type::Func(id) => Ok(Type::Func(self.remap_func_type(types, id, checker)?)),
526            Type::Value(ty) => Ok(Type::Value(self.remap_value_type(types, ty, checker)?)),
527            Type::Interface(id) => Ok(Type::Interface(self.remap_interface(types, id, checker)?)),
528            Type::World(id) => Ok(Type::World(self.remap_world(types, id, checker)?)),
529            Type::Module(id) => Ok(Type::Module(self.remap_module_type(types, id))),
530        }
531    }
532
533    fn remap_resource(
534        &mut self,
535        types: &Types,
536        id: ResourceId,
537        checker: &mut SubtypeChecker,
538    ) -> Result<ResourceId> {
539        if let Some(kind) = self.remapped.get(&Type::Resource(id)) {
540            return match kind {
541                Type::Resource(id) => Ok(*id),
542                _ => panic!("expected a resource"),
543            };
544        }
545
546        let resource = &types[id];
547        let remapped = Resource {
548            name: resource.name.clone(),
549            alias: resource
550                .alias
551                .map(|a| -> Result<_> {
552                    let owner = a
553                        .owner
554                        .map(|id| {
555                            // There's no need to merge the interface here as
556                            // merging is done as part of the interface remapping
557                            self.remap_interface(types, id, checker)
558                        })
559                        .transpose()?;
560                    // If there is an owning interface, ensure it is imported
561                    if let Some(owner) = owner {
562                        let name = self.types()[owner]
563                            .id
564                            .as_deref()
565                            .expect("interface has no id");
566                        if !self.imports.contains_key(name) {
567                            self.imports
568                                .insert(name.to_owned(), ItemKind::Instance(owner));
569                        }
570                    }
571                    Ok(ResourceAlias {
572                        owner,
573                        source: self.remap_resource(types, a.source, checker)?,
574                    })
575                })
576                .transpose()?,
577        };
578        let remapped_id = self.types.add_resource(remapped);
579
580        let prev = self
581            .remapped
582            .insert(Type::Resource(id), Type::Resource(remapped_id));
583        assert!(prev.is_none());
584        Ok(remapped_id)
585    }
586
587    fn remap_func_type(
588        &mut self,
589        types: &Types,
590        id: FuncTypeId,
591        checker: &mut SubtypeChecker,
592    ) -> Result<FuncTypeId> {
593        if let Some(kind) = self.remapped.get(&Type::Func(id)) {
594            return match kind {
595                Type::Func(id) => Ok(*id),
596                _ => panic!("expected a function type"),
597            };
598        }
599
600        let ty = &types[id];
601        let remapped = FuncType {
602            params: ty
603                .params
604                .iter()
605                .map(|(n, ty)| Ok((n.clone(), self.remap_value_type(types, *ty, checker)?)))
606                .collect::<Result<_>>()?,
607            result: ty
608                .result
609                .map(|ty| self.remap_value_type(types, ty, checker))
610                .transpose()?,
611        };
612
613        let remapped_id = self.types.add_func_type(remapped);
614        let prev = self
615            .remapped
616            .insert(Type::Func(id), Type::Func(remapped_id));
617        assert!(prev.is_none());
618        Ok(remapped_id)
619    }
620
621    fn remap_value_type(
622        &mut self,
623        types: &Types,
624        ty: ValueType,
625        checker: &mut SubtypeChecker,
626    ) -> Result<ValueType> {
627        match ty {
628            ValueType::Primitive(ty) => Ok(ValueType::Primitive(ty)),
629            ValueType::Borrow(id) => {
630                Ok(ValueType::Borrow(self.remap_resource(types, id, checker)?))
631            }
632            ValueType::Own(id) => Ok(ValueType::Own(self.remap_resource(types, id, checker)?)),
633            ValueType::Defined(id) => Ok(ValueType::Defined(
634                self.remap_defined_type(types, id, checker)?,
635            )),
636        }
637    }
638
639    fn remap_interface(
640        &mut self,
641        types: &Types,
642        id: InterfaceId,
643        checker: &mut SubtypeChecker,
644    ) -> Result<InterfaceId> {
645        // If we've seen this interface before, perform a merge
646        // This will ensure that there's only a singular definition of "named" interfaces
647        if let Some(name) = types[id].id.as_ref() {
648            if let Some(existing) = self.interfaces.get(name).copied() {
649                self.merge_interface(existing, types, id, checker)
650                    .with_context(|| format!("failed to merge interface `{name}`"))?;
651                return Ok(existing);
652            }
653        }
654
655        if let Some(kind) = self.remapped.get(&Type::Interface(id)) {
656            return match kind {
657                Type::Interface(id) => Ok(*id),
658                _ => panic!("expected an interface"),
659            };
660        }
661
662        let ty = &types[id];
663        let interface = Interface {
664            id: ty.id.clone(),
665            uses: ty
666                .uses
667                .iter()
668                .map(|(n, u)| {
669                    if types[u.interface].id.is_none() {
670                        bail!("used type `{n}` is from an interface without an identifier");
671                    }
672
673                    Ok((
674                        n.clone(),
675                        UsedType {
676                            interface: self.remap_interface(types, u.interface, checker)?,
677                            name: u.name.clone(),
678                        },
679                    ))
680                })
681                .collect::<Result<_>>()?,
682            exports: ty
683                .exports
684                .iter()
685                .map(|(n, k)| Ok((n.clone(), self.remap_item_kind(types, *k, checker)?)))
686                .collect::<Result<_>>()?,
687        };
688
689        let remapped = self.types.add_interface(interface);
690        let prev = self
691            .remapped
692            .insert(Type::Interface(id), Type::Interface(remapped));
693        assert!(prev.is_none());
694
695        if let Some(name) = self.types[remapped].id.as_ref() {
696            let prev = self.interfaces.insert(name.clone(), remapped);
697            assert!(prev.is_none());
698        }
699
700        Ok(remapped)
701    }
702
703    fn remap_world(
704        &mut self,
705        types: &Types,
706        id: WorldId,
707        checker: &mut SubtypeChecker,
708    ) -> Result<WorldId> {
709        if let Some(kind) = self.remapped.get(&Type::World(id)) {
710            return match kind {
711                Type::World(id) => Ok(*id),
712                _ => panic!("expected a world"),
713            };
714        }
715
716        let ty = &types[id];
717        let world = World {
718            id: ty.id.clone(),
719            uses: ty
720                .uses
721                .iter()
722                .map(|(n, u)| {
723                    if types[u.interface].id.is_none() {
724                        bail!("used type `{n}` is from an interface without an identifier");
725                    }
726
727                    Ok((
728                        n.clone(),
729                        UsedType {
730                            interface: self.remap_interface(types, u.interface, checker)?,
731                            name: u.name.clone(),
732                        },
733                    ))
734                })
735                .collect::<Result<_>>()?,
736            imports: ty
737                .imports
738                .iter()
739                .map(|(n, k)| Ok((n.clone(), self.remap_item_kind(types, *k, checker)?)))
740                .collect::<Result<_>>()?,
741            exports: ty
742                .exports
743                .iter()
744                .map(|(n, k)| Ok((n.clone(), self.remap_item_kind(types, *k, checker)?)))
745                .collect::<Result<_>>()?,
746        };
747
748        let remapped = self.types.add_world(world);
749        let prev = self.remapped.insert(Type::World(id), Type::World(remapped));
750        assert!(prev.is_none());
751
752        Ok(remapped)
753    }
754
755    fn remap_module_type(&mut self, types: &Types, id: ModuleTypeId) -> ModuleTypeId {
756        if let Some(kind) = self.remapped.get(&Type::Module(id)) {
757            return match kind {
758                Type::Module(id) => *id,
759                _ => panic!("expected a module type"),
760            };
761        }
762
763        let ty = &types[id];
764        let remapped = self.types.add_module_type(ty.clone());
765        let prev = self
766            .remapped
767            .insert(Type::Module(id), Type::Module(remapped));
768        assert!(prev.is_none());
769        remapped
770    }
771
772    fn remap_defined_type(
773        &mut self,
774        types: &Types,
775        id: DefinedTypeId,
776        checker: &mut SubtypeChecker,
777    ) -> Result<DefinedTypeId> {
778        if let Some(kind) = self.remapped.get(&Type::Value(ValueType::Defined(id))) {
779            return match kind {
780                Type::Value(ValueType::Defined(id)) => Ok(*id),
781                _ => panic!("expected a defined type got {kind:?}"),
782            };
783        }
784
785        let defined = match &types[id] {
786            DefinedType::Tuple(tys) => DefinedType::Tuple(
787                tys.iter()
788                    .map(|ty| self.remap_value_type(types, *ty, checker))
789                    .collect::<Result<_>>()?,
790            ),
791            DefinedType::List(ty) => DefinedType::List(self.remap_value_type(types, *ty, checker)?),
792            DefinedType::FixedSizeList(ty, elements) => {
793                DefinedType::FixedSizeList(self.remap_value_type(types, *ty, checker)?, *elements)
794            }
795            DefinedType::Option(ty) => {
796                DefinedType::Option(self.remap_value_type(types, *ty, checker)?)
797            }
798            DefinedType::Result { ok, err } => DefinedType::Result {
799                ok: ok
800                    .as_ref()
801                    .map(|ty| self.remap_value_type(types, *ty, checker))
802                    .transpose()?,
803                err: err
804                    .as_ref()
805                    .map(|ty| self.remap_value_type(types, *ty, checker))
806                    .transpose()?,
807            },
808            DefinedType::Variant(v) => DefinedType::Variant(Variant {
809                cases: v
810                    .cases
811                    .iter()
812                    .map(|(n, ty)| {
813                        Ok((
814                            n.clone(),
815                            ty.as_ref()
816                                .map(|ty| self.remap_value_type(types, *ty, checker))
817                                .transpose()?,
818                        ))
819                    })
820                    .collect::<Result<_>>()?,
821            }),
822            DefinedType::Record(r) => DefinedType::Record(Record {
823                fields: r
824                    .fields
825                    .iter()
826                    .map(|(n, ty)| Ok((n.clone(), self.remap_value_type(types, *ty, checker)?)))
827                    .collect::<Result<_>>()?,
828            }),
829            DefinedType::Flags(f) => DefinedType::Flags(f.clone()),
830            DefinedType::Enum(e) => DefinedType::Enum(e.clone()),
831            DefinedType::Alias(ty) => {
832                DefinedType::Alias(self.remap_value_type(types, *ty, checker)?)
833            }
834            DefinedType::Stream(s) => DefinedType::Stream(
835                s.as_ref()
836                    .map(|ty| self.remap_value_type(types, *ty, checker))
837                    .transpose()?,
838            ),
839            DefinedType::Future(f) => DefinedType::Future(
840                f.as_ref()
841                    .map(|ty| self.remap_value_type(types, *ty, checker))
842                    .transpose()?,
843            ),
844        };
845
846        let remapped = self.types.add_defined_type(defined);
847        let prev = self.remapped.insert(
848            Type::Value(ValueType::Defined(id)),
849            Type::Value(ValueType::Defined(remapped)),
850        );
851        assert!(prev.is_none());
852        Ok(remapped)
853    }
854}