Skip to main content

hyperlight_component_util/
elaborate.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 The Hyperlight Authors.
3
4//! Component type elaboration
5//!
6//! This is a pretty direct port of the relevant sections of the OCaml
7//! reference interpreter, except that the approach to substitutions has
8//! been changed significantly. (Although the core capture-avoiding
9//! substitution routines are of course the same, the ways in which
10//! substitutions are represented/constructed are quite different; see
11//! substitute.rs for more details of the approach here).
12
13use wasmparser::{
14    ComponentAlias, ComponentDefinedType, ComponentExternName, ComponentFuncType,
15    ComponentOuterAliasKind, ComponentType, ComponentTypeDeclaration, ComponentTypeRef,
16    ComponentValType, CompositeInnerType, CoreType, InstanceTypeDeclaration, ModuleTypeDeclaration,
17    OuterAliasKind, PrimitiveValType, TypeBounds, TypeRef,
18};
19
20use crate::etypes::{
21    BoundedTyvar, Component, CoreDefined, CoreExportDecl, CoreExternDesc, CoreModule,
22    CoreOrComponentExternDesc, Ctx, Defined, ExternDecl, ExternDesc, FloatWidth, Func, Handleable,
23    Instance, IntWidth, Name, Param, QualifiedInstance, RecordField, Resource, ResourceId,
24    TypeBound, Tyvar, Value, VariantCase,
25};
26use crate::substitute::{self, Substitution, Unvoidable};
27use crate::tv::ResolvedTyvar;
28use crate::wf;
29
30mod basic_conversions {
31    //! Basic utility conversions between various spec and wasmparser
32    //! representations of extern kind/sorts
33
34    use wasmparser::{ComponentExternalKind, ExternalKind};
35
36    use crate::etypes::{CoreExternDesc, ExternDesc};
37    use crate::structure::{CoreSort, Sort};
38
39    pub(super) fn sort_matches_core_ed(sort: Sort, ed: &CoreExternDesc) {
40        match (sort, ed) {
41            (Sort::Core(CoreSort::Func), CoreExternDesc::Func(_)) => (),
42            (Sort::Core(CoreSort::Table), CoreExternDesc::Table(_)) => (),
43            (Sort::Core(CoreSort::Memory), CoreExternDesc::Memory(_)) => (),
44            (Sort::Core(CoreSort::Global), CoreExternDesc::Global(_)) => (),
45            _ => panic!("sort does not match core extern descriptor"),
46        }
47    }
48
49    pub(super) fn external_kind(k: ExternalKind) -> Sort {
50        match k {
51            ExternalKind::Func => Sort::Core(CoreSort::Func),
52            ExternalKind::Table => Sort::Core(CoreSort::Table),
53            ExternalKind::Memory => Sort::Core(CoreSort::Memory),
54            ExternalKind::Global => Sort::Core(CoreSort::Global),
55            ExternalKind::Tag => panic!("core type tags are not supported"),
56            ExternalKind::FuncExact => panic!("core type exact functions are not supported"),
57        }
58    }
59
60    pub(super) fn sort_matches_ed<'a>(sort: Sort, ed: &ExternDesc<'a>) {
61        match (sort, ed) {
62            (Sort::Core(CoreSort::Module), ExternDesc::CoreModule(_)) => (),
63            (Sort::Func, ExternDesc::Func(_)) => (),
64            (Sort::Type, ExternDesc::Type(_)) => (),
65            (Sort::Instance, ExternDesc::Instance(_)) => (),
66            (Sort::Component, ExternDesc::Component(_)) => (),
67            _ => panic!("sort does not match extern descriptor"),
68        }
69    }
70
71    pub(super) fn component_external_kind(k: ComponentExternalKind) -> Sort {
72        match k {
73            ComponentExternalKind::Module => Sort::Core(CoreSort::Module),
74            ComponentExternalKind::Func => Sort::Func,
75            ComponentExternalKind::Value => Sort::Value,
76            ComponentExternalKind::Type => Sort::Type,
77            ComponentExternalKind::Instance => Sort::Instance,
78            ComponentExternalKind::Component => Sort::Component,
79        }
80    }
81}
82use basic_conversions::*;
83
84#[derive(Debug)]
85#[allow(dead_code)]
86/// Elaboration-specific errors
87pub enum Error<'a> {
88    /// Innerizing an outer alias failed; this usually means that the
89    /// outer alias refers to a resource type or something like that.
90    InvalidOuterAlias(substitute::InnerizeError),
91    /// Innerizing an outer alias resulted in an ill-formed type; this
92    /// often also means that the outer alias refers to a resource
93    /// type or similar.
94    IllFormedOuterAlias(wf::Error<'a>),
95    /// The component type declarator should never have a resource
96    /// type in it, even though this is allowed by the grammar, since
97    /// there is no export (or instantiation) to generatively give it
98    /// identity.
99    ResourceInDeclarator,
100    /// A the typeidx inside an own/borrow handle should always point
101    /// to a resource type (either a bare resource, or, more usually,
102    /// an imported/exported type variable that is bounded by `(sub
103    /// resource)`.
104    HandleToNonResource,
105    /// Complex valtypes are allowed to use indirect type indices to
106    /// refer to another type, but the type index space is also used
107    /// for instance types, bare resource types, etc.  A malformed
108    /// complex value type which refers to a non-value type will
109    /// result in this error.
110    ValTypeRefToNonVal(Defined<'a>),
111    /// The finalisation/closing of a component or instance type
112    /// failed. This usually means that an exported type is referring
113    /// to a non-exported type variable or something along those
114    /// lines, which makes it impossible for the exported type to be
115    /// lifted out of the context.
116    ClosingError(substitute::ClosingError),
117    /// A finished component or instance type was ill-formed
118    IllFormed(wf::Error<'a>),
119}
120impl<'a> From<substitute::ClosingError> for Error<'a> {
121    fn from(e: substitute::ClosingError) -> Error<'a> {
122        Error::ClosingError(e)
123    }
124}
125
126/// # Elaboration
127///
128/// Most of this is a very direct translation of the specification
129/// (section 3.4 Type Elaboration).
130impl<'p, 'a> Ctx<'p, 'a> {
131    pub fn elab_component<'c>(
132        &'c mut self,
133        decls: &[ComponentTypeDeclaration<'a>],
134    ) -> Result<Component<'a>, Error<'a>> {
135        let mut ctx = Ctx::new(Some(self), false);
136        let mut imports = Vec::new();
137        let mut exports = Vec::new();
138        for decl in decls {
139            let (import, export) = ctx.elab_component_decl(decl)?;
140            if let Some(import) = import {
141                imports.push(import);
142            }
143            if let Some(export) = export {
144                exports.push(export);
145            }
146        }
147        ctx.finish_component(&imports, &exports)
148    }
149
150    fn elab_core_module_decl<'c>(
151        &'c mut self,
152        decl: &ModuleTypeDeclaration<'a>,
153    ) -> (Option<wasmparser::Import<'a>>, Option<CoreExportDecl<'a>>) {
154        match decl {
155            ModuleTypeDeclaration::Import(i) => (Some(*i), None),
156            ModuleTypeDeclaration::Type(rg) => {
157                let ct = self.elab_core_type_rec(rg);
158                self.core.types.push(ct);
159                (None, None)
160            }
161            ModuleTypeDeclaration::OuterAlias {
162                kind: OuterAliasKind::Type,
163                count,
164                index,
165            } => {
166                let ct = self.parents().nth(*count as usize).unwrap().core.types[*index as usize]
167                    .clone();
168                self.core.types.push(ct);
169                (None, None)
170            }
171            ModuleTypeDeclaration::Export { name, ty } => (
172                None,
173                Some(CoreExportDecl {
174                    name: Name { name },
175                    desc: match ty {
176                        TypeRef::Func(n) => match &self.core.types[*n as usize] {
177                            CoreDefined::Func(ft) => CoreExternDesc::Func(ft.clone()),
178                            _ => panic!(
179                                "internal invariant violation: WasmParser function TypeRef refers to non-function"
180                            ),
181                        },
182                        TypeRef::Table(tt) => CoreExternDesc::Table(*tt),
183                        TypeRef::Memory(mt) => CoreExternDesc::Memory(*mt),
184                        TypeRef::Global(gt) => CoreExternDesc::Global(*gt),
185                        TypeRef::Tag(_) => panic!("core type tags are not supported"),
186                        TypeRef::FuncExact(_) => {
187                            panic!("core type exact functions are not supported")
188                        }
189                    },
190                }),
191            ),
192        }
193    }
194
195    fn elab_core_module<'c>(&'c mut self, decls: &[ModuleTypeDeclaration<'a>]) -> CoreModule<'a> {
196        let mut ctx = Ctx::new(Some(self), false);
197        let mut imports = Vec::new();
198        let mut exports = Vec::new();
199        for decl in decls {
200            let (import, export) = ctx.elab_core_module_decl(decl);
201            if let Some(import) = import {
202                imports.push(import)
203            }
204            if let Some(export) = export {
205                exports.push(export)
206            }
207        }
208        CoreModule {
209            _imports: imports,
210            _exports: exports,
211        }
212    }
213
214    fn elab_core_type_rec<'c>(&'c mut self, rg: &wasmparser::RecGroup) -> CoreDefined<'a> {
215        match &rg.types().nth(0).unwrap().composite_type.inner {
216            CompositeInnerType::Func(ft) => CoreDefined::Func(ft.clone()),
217            _ => panic!("GC core types are not presently supported"),
218        }
219    }
220
221    fn elab_core_type<'c>(&'c mut self, ct: &wasmparser::CoreType<'a>) -> CoreDefined<'a> {
222        match ct {
223            CoreType::Rec(rg) => self.elab_core_type_rec(rg),
224            CoreType::Module(ds) => CoreDefined::Module(self.elab_core_module(ds)),
225        }
226    }
227
228    /// This tries to handle pretty much everything involved in alias
229    /// resolution and well-formedness checking. Since both core and
230    /// component aliases are largely similar, it can handle both and
231    /// has to return a union of core/component extern descriptors
232    /// that does not exist in the spec.
233    fn resolve_alias<'c>(
234        &'c mut self,
235        alias: &ComponentAlias<'a>,
236    ) -> Result<CoreOrComponentExternDesc<'a>, Error<'a>> {
237        match alias {
238            ComponentAlias::InstanceExport {
239                kind,
240                instance_index,
241                name,
242            } => {
243                let it = &self.instances[*instance_index as usize];
244                let ed = &it
245                    .exports
246                    .iter()
247                    .find(|e| e.kebab_name == *name)
248                    .unwrap()
249                    .desc;
250                let sort = component_external_kind(*kind);
251                sort_matches_ed(sort, ed);
252                Ok(CoreOrComponentExternDesc::Component(ed.clone()))
253            }
254            ComponentAlias::CoreInstanceExport {
255                kind,
256                instance_index,
257                name,
258            } => {
259                let it = &self.core.instances[*instance_index as usize];
260                let ed = &it
261                    .exports
262                    .iter()
263                    .find(|e| e.name.name == *name)
264                    .unwrap()
265                    .desc;
266                let sort = external_kind(*kind);
267                sort_matches_core_ed(sort, ed);
268                Ok(CoreOrComponentExternDesc::Core(ed.clone()))
269            }
270            ComponentAlias::Outer { kind, count, index } => {
271                if *kind != ComponentOuterAliasKind::Type {
272                    panic!("In types, only outer type aliases are allowed");
273                }
274                // Walk through each of the contexts between us and
275                // the targeted type, so that we can innerize each one
276                let mut ctxs = self.parents().take(*count as usize + 1).collect::<Vec<_>>();
277                ctxs.reverse();
278                let mut target_type = ctxs[0].types[*index as usize].clone();
279                let mut ob_crossed = false;
280                for ctxs_ in ctxs.windows(2) {
281                    ob_crossed |= ctxs_[1].outer_boundary;
282                    let sub = substitute::Innerize::new(ctxs_[0], ctxs_[1].outer_boundary);
283                    target_type = sub
284                        .defined(&target_type)
285                        .map_err(Error::InvalidOuterAlias)?;
286                }
287                if ob_crossed {
288                    self.wf_defined(wf::DefinedTypePosition::export(), &target_type)
289                        .map_err(Error::IllFormedOuterAlias)?;
290                }
291                Ok(CoreOrComponentExternDesc::Component(ExternDesc::Type(
292                    target_type,
293                )))
294            }
295        }
296    }
297
298    /// Add a core extern descriptor to the context: whatever it
299    /// describes is added to the relevant index space
300    fn add_core_ed<'c>(&'c mut self, ed: CoreExternDesc) {
301        match ed {
302            CoreExternDesc::Func(ft) => self.core.funcs.push(ft),
303            CoreExternDesc::Table(tt) => self.core.tables.push(tt),
304            CoreExternDesc::Memory(mt) => self.core.mems.push(mt),
305            CoreExternDesc::Global(gt) => self.core.globals.push(gt),
306        }
307    }
308
309    /// Add an extern descriptor to the context: whatever it describes
310    /// is added to the relevant index space. Note that this does not
311    /// handle stripping the type variables off of an instance type
312    /// (since `ExternDesc::Instance` doesn't have them); that should
313    /// have been done earlier. See for example the export instance
314    /// declarator case below, which converts the bound variables on
315    /// the instance type to context evars, and fixes them up in the
316    /// instance type, before calling add_ed.
317    fn add_ed<'c>(&'c mut self, ed: &ExternDesc<'a>) {
318        match ed {
319            ExternDesc::CoreModule(cmd) => self.core.modules.push(cmd.clone()),
320            ExternDesc::Func(ft) => self.funcs.push(ft.clone()),
321            ExternDesc::Type(dt) => self.types.push(dt.clone()),
322            ExternDesc::Instance(it) => self.instances.push(it.clone()),
323            ExternDesc::Component(ct) => self.components.push(ct.clone()),
324        }
325    }
326
327    fn add_core_or_component_ed<'c>(&'c mut self, ed: CoreOrComponentExternDesc<'a>) {
328        match ed {
329            CoreOrComponentExternDesc::Core(ced) => self.add_core_ed(ced),
330            CoreOrComponentExternDesc::Component(ed) => self.add_ed(&ed),
331        }
332    }
333
334    fn elab_value<'c>(&'c mut self, ctr: &ComponentValType) -> Result<Value<'a>, Error<'a>> {
335        match ctr {
336            ComponentValType::Type(n) => match &self.types[*n as usize] {
337                Defined::Value(vt) => Ok(vt.clone()),
338                dt @ Defined::Handleable(Handleable::Var(tv)) => match self.resolve_tyvar(tv) {
339                    ResolvedTyvar::Definite(Defined::Value(vt)) => {
340                        Ok(Value::Var(Some(tv.clone()), Box::new(vt)))
341                    }
342                    _ => Err(Error::ValTypeRefToNonVal(dt.clone())),
343                },
344                dt => Err(Error::ValTypeRefToNonVal(dt.clone())),
345            },
346            ComponentValType::Primitive(pt) => Ok(match pt {
347                PrimitiveValType::Bool => Value::Bool,
348                PrimitiveValType::S8 => Value::S(IntWidth::I8),
349                PrimitiveValType::U8 => Value::U(IntWidth::I8),
350                PrimitiveValType::S16 => Value::S(IntWidth::I16),
351                PrimitiveValType::U16 => Value::U(IntWidth::I16),
352                PrimitiveValType::S32 => Value::S(IntWidth::I32),
353                PrimitiveValType::U32 => Value::U(IntWidth::I32),
354                PrimitiveValType::S64 => Value::S(IntWidth::I64),
355                PrimitiveValType::U64 => Value::U(IntWidth::I64),
356                PrimitiveValType::F32 => Value::F(FloatWidth::F32),
357                PrimitiveValType::F64 => Value::F(FloatWidth::F64),
358                PrimitiveValType::Char => Value::Char,
359                PrimitiveValType::String => Value::String,
360                PrimitiveValType::ErrorContext => panic!("async not yet supported"),
361            }),
362        }
363    }
364
365    fn elab_defined_value<'c>(
366        &'c mut self,
367        vt: &ComponentDefinedType<'a>,
368    ) -> Result<Value<'a>, Error<'a>> {
369        match vt {
370            ComponentDefinedType::Primitive(pvt) => {
371                self.elab_value(&ComponentValType::Primitive(*pvt))
372            }
373            ComponentDefinedType::Record(rfs) => {
374                let rfs = rfs
375                    .iter()
376                    .map(|(name, ty)| {
377                        Ok::<_, Error<'a>>(RecordField {
378                            name: Name { name },
379                            ty: self.elab_value(ty)?,
380                        })
381                    })
382                    .collect::<Result<Vec<_>, Error<'a>>>()?;
383                Ok(Value::Record(rfs))
384            }
385            ComponentDefinedType::Variant(vcs) => {
386                let vcs = vcs
387                    .iter()
388                    .map(|vc| {
389                        Ok(VariantCase {
390                            name: Name { name: vc.name },
391                            ty: vc.ty.as_ref().map(|ty| self.elab_value(ty)).transpose()?,
392                        })
393                    })
394                    .collect::<Result<Vec<_>, Error<'a>>>()?;
395                Ok(Value::Variant(vcs))
396            }
397            ComponentDefinedType::List(vt) => Ok(Value::List(Box::new(self.elab_value(vt)?))),
398            ComponentDefinedType::Tuple(vts) => Ok(Value::Tuple(
399                vts.iter()
400                    .map(|vt| self.elab_value(vt))
401                    .collect::<Result<Vec<_>, Error<'a>>>()?,
402            )),
403            ComponentDefinedType::Flags(ns) => {
404                Ok(Value::Flags(ns.iter().map(|n| Name { name: n }).collect()))
405            }
406            ComponentDefinedType::Enum(ns) => {
407                Ok(Value::Enum(ns.iter().map(|n| Name { name: n }).collect()))
408            }
409            ComponentDefinedType::Option(vt) => Ok(Value::Option(Box::new(self.elab_value(vt)?))),
410            ComponentDefinedType::Result { ok, err } => Ok(Value::Result(
411                Box::new(ok.map(|ok| self.elab_value(&ok)).transpose()?),
412                Box::new(err.map(|err| self.elab_value(&err)).transpose()?),
413            )),
414            ComponentDefinedType::Own(n) => match &self.types[*n as usize] {
415                Defined::Handleable(h) => Ok(Value::Own(h.clone())),
416                _ => Err(Error::HandleToNonResource),
417            },
418            ComponentDefinedType::Borrow(n) => match &self.types[*n as usize] {
419                Defined::Handleable(h) => Ok(Value::Borrow(h.clone())),
420                _ => Err(Error::HandleToNonResource),
421            },
422            ComponentDefinedType::FixedLengthList(vt, size) => {
423                Ok(Value::FixList(Box::new(self.elab_value(vt)?), *size))
424            }
425            ComponentDefinedType::Future(_) | ComponentDefinedType::Stream(_) => {
426                panic!("async not yet supported")
427            }
428            ComponentDefinedType::Map(_, _) => {
429                panic!("map type not yet supported")
430            }
431        }
432    }
433
434    fn elab_func<'c>(&'c mut self, ft: &ComponentFuncType<'a>) -> Result<Func<'a>, Error<'a>> {
435        if ft.async_ {
436            panic!("async not yet supported")
437        }
438        Ok(Func {
439            params: ft
440                .params
441                .iter()
442                .map(|(n, vt)| {
443                    Ok(Param {
444                        name: Name { name: n },
445                        ty: self.elab_value(vt)?,
446                    })
447                })
448                .collect::<Result<Vec<_>, Error<'a>>>()?,
449            result: ft
450                .result
451                .as_ref()
452                .map(|vt| self.elab_value(vt))
453                .transpose()?,
454        })
455    }
456
457    /// Elaborate an extern descriptor. This returns any evars that
458    /// are implied by the descriptor separately, to simplify
459    /// converting them to context e/u vars, which is usually what you
460    /// want to do.
461    fn elab_extern_desc<'c>(
462        &'c mut self,
463        ed: &ComponentTypeRef,
464    ) -> Result<(Vec<BoundedTyvar<'a>>, ExternDesc<'a>), Error<'a>> {
465        match ed {
466            ComponentTypeRef::Module(i) => match &self.core.types[*i as usize] {
467                CoreDefined::Module(mt) => Ok((vec![], ExternDesc::CoreModule(mt.clone()))),
468                _ => {
469                    panic!("internal invariant violation: bad sort for ComponentTypeRef to Module")
470                }
471            },
472            ComponentTypeRef::Func(i) => match &self.types[*i as usize] {
473                Defined::Func(ft) => Ok((vec![], ExternDesc::Func(ft.clone()))),
474                _ => panic!("internal invariant violation: bad sort for ComponentTypeRef to Func"),
475            },
476            ComponentTypeRef::Value(_) => panic!("First-class values are not yet supported"),
477            ComponentTypeRef::Type(tb) => {
478                let bound = match tb {
479                    TypeBounds::Eq(i) => TypeBound::Eq(self.types[*i as usize].clone()),
480                    TypeBounds::SubResource => TypeBound::SubResource,
481                };
482                let dt = Defined::Handleable(Handleable::Var(Tyvar::Bound(0)));
483                Ok((vec![BoundedTyvar::new(bound)], ExternDesc::Type(dt)))
484            }
485            ComponentTypeRef::Instance(i) => match &self.types[*i as usize] {
486                Defined::Instance(qit) => Ok((
487                    qit.evars.clone(),
488                    ExternDesc::Instance(qit.unqualified.clone()),
489                )),
490                _ => panic!(
491                    "internal invariant violation: bad sort for ComponentTypeRef to Instance"
492                ),
493            },
494            ComponentTypeRef::Component(i) => match &self.types[*i as usize] {
495                Defined::Component(ct) => Ok((vec![], ExternDesc::Component(ct.clone()))),
496                _ => panic!(
497                    "internal invariant violation: bad sort for ComponentTypeRef to Component"
498                ),
499            },
500        }
501    }
502
503    fn elab_instance_decl<'c>(
504        &'c mut self,
505        decl: &InstanceTypeDeclaration<'a>,
506    ) -> Result<Option<ExternDecl<'a>>, Error<'a>> {
507        match decl {
508            InstanceTypeDeclaration::CoreType(ct) => {
509                let ct = self.elab_core_type(ct);
510                self.core.types.push(ct);
511                Ok(None)
512            }
513            InstanceTypeDeclaration::Type(t) => {
514                let t = self.elab_defined(t)?;
515                if let Defined::Handleable(_) = t {
516                    return Err(Error::ResourceInDeclarator);
517                }
518                self.types.push(t);
519                Ok(None)
520            }
521            InstanceTypeDeclaration::Alias(a) => {
522                let ed = self.resolve_alias(a)?;
523                self.add_core_or_component_ed(ed);
524                Ok(None)
525            }
526            InstanceTypeDeclaration::Export {
527                name: export_name,
528                ty,
529            } => {
530                let ComponentExternName {
531                    name: kebab_name, ..
532                } = *export_name;
533                let (vs, ed) = self.elab_extern_desc(ty)?;
534                let sub = self.bound_to_evars(Some(kebab_name), &vs);
535                let ed = sub.extern_desc(&ed).not_void();
536                self.add_ed(&ed);
537                Ok(Some(ExternDecl {
538                    kebab_name,
539                    desc: ed,
540                }))
541            }
542        }
543    }
544
545    fn elab_instance<'c>(
546        &'c mut self,
547        decls: &[InstanceTypeDeclaration<'a>],
548    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
549        let mut ctx = Ctx::new(Some(self), false);
550        let mut exports = Vec::new();
551        for decl in decls {
552            let export = ctx.elab_instance_decl(decl)?;
553            if let Some(export) = export {
554                exports.push(export);
555            }
556        }
557        ctx.finish_instance(&exports)
558    }
559
560    /// Convert instance variables in the context into bound variables
561    /// in the type. This is pulled out separately from raising the
562    /// resulting type so that it can be shared between
563    /// [`Ctx::finish_instance`] and [`Ctx::finish_component`], which
564    /// have different requirements in that respect.
565    fn finish_instance_evars(
566        self,
567        exports: &[ExternDecl<'a>],
568    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
569        let mut evars = Vec::new();
570        let mut sub = substitute::Closing::new(false);
571        for (bound, _) in self.evars {
572            let bound = sub.bounded_tyvar(&bound)?;
573            evars.push(bound);
574            sub.next_e();
575        }
576        let unqualified = sub.instance(&Instance {
577            exports: exports.to_vec(),
578        })?;
579        Ok(QualifiedInstance { evars, unqualified })
580    }
581
582    /// The equivalent of the \oplus in the spec.  This has to deal
583    /// with more bookkeeping because of our variable representation:
584    /// the free variables in the exports need to be converted to
585    /// bound variables, and any free variables referring to upper
586    /// contexts need to have their parent/outer index reduced by one
587    /// to deal with this context ending.
588    fn finish_instance(
589        self,
590        exports: &[ExternDecl<'a>],
591    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
592        // When we do the well-formedness check in a minute, we need
593        // to use the parent ctx, because the closing substitution has
594        // already been applied.
595        let fallback_parent = Ctx::new(None, false);
596        let parent_ctx = self.parent.unwrap_or(&fallback_parent);
597
598        let qi = self.finish_instance_evars(exports)?;
599        let raise_u_sub = substitute::Closing::new(true);
600        let it = raise_u_sub.qualified_instance(&qi)?;
601        parent_ctx
602            .wf_qualified_instance(wf::DefinedTypePosition::internal(), &it)
603            .map_err(Error::IllFormed)?;
604        Ok(it)
605    }
606
607    fn elab_component_decl<'c>(
608        &'c mut self,
609        decl: &ComponentTypeDeclaration<'a>,
610    ) -> Result<(Option<ExternDecl<'a>>, Option<ExternDecl<'a>>), Error<'a>> {
611        match decl {
612            ComponentTypeDeclaration::CoreType(ct) => {
613                let ct = self.elab_core_type(ct);
614                self.core.types.push(ct);
615                Ok((None, None))
616            }
617            ComponentTypeDeclaration::Type(t) => {
618                let t = self.elab_defined(t)?;
619                if let Defined::Handleable(_) = t {
620                    return Err(Error::ResourceInDeclarator);
621                }
622                self.types.push(t);
623                Ok((None, None))
624            }
625            ComponentTypeDeclaration::Alias(a) => {
626                let ed = self.resolve_alias(a)?;
627                self.add_core_or_component_ed(ed);
628                Ok((None, None))
629            }
630            ComponentTypeDeclaration::Export {
631                name: export_name,
632                ty,
633                ..
634            } => {
635                let ComponentExternName {
636                    name: kebab_name, ..
637                } = *export_name;
638                let (vs, ed) = self.elab_extern_desc(ty)?;
639                let sub = self.bound_to_evars(Some(kebab_name), &vs);
640                let ed = sub.extern_desc(&ed).not_void();
641                self.add_ed(&ed);
642                Ok((
643                    None,
644                    Some(ExternDecl {
645                        kebab_name,
646                        desc: ed,
647                    }),
648                ))
649            }
650            ComponentTypeDeclaration::Import(i) => {
651                let ComponentExternName {
652                    name: kebab_name, ..
653                } = i.name;
654                let (vs, ed) = self.elab_extern_desc(&i.ty)?;
655                let sub = self.bound_to_uvars(Some(kebab_name), &vs, true);
656                let ed = sub.extern_desc(&ed).not_void();
657                self.add_ed(&ed);
658                Ok((
659                    Some(ExternDecl {
660                        kebab_name,
661                        desc: ed,
662                    }),
663                    None,
664                ))
665            }
666        }
667    }
668
669    /// Similar to [`Ctx::finish_instance`], but for components; this
670    /// has to cover uvars as well as evars.
671    fn finish_component(
672        self,
673        imports: &[ExternDecl<'a>],
674        exports: &[ExternDecl<'a>],
675    ) -> Result<Component<'a>, Error<'a>> {
676        // When we do the well-formedness check in a minute, we need
677        // to use the parent ctx, because the closing substitution has
678        // already been applied.
679        let fallback_parent = Ctx::new(None, false);
680        let parent_ctx = self.parent.unwrap_or(&fallback_parent);
681
682        let mut uvars = Vec::new();
683        let mut sub = substitute::Closing::new(true);
684        for (bound, imported) in &self.uvars {
685            let bound = sub.bounded_tyvar(bound)?;
686            uvars.push(bound);
687            sub.next_u(*imported);
688        }
689        let imports = imports
690            .iter()
691            .map(|ed| sub.extern_decl(ed).map_err(Into::into))
692            .collect::<Result<Vec<ExternDecl<'a>>, Error<'a>>>()?;
693        let instance = sub.qualified_instance(&self.finish_instance_evars(exports)?)?;
694        let ct = Component {
695            uvars,
696            imports,
697            instance,
698        };
699        parent_ctx
700            .wf_component(wf::DefinedTypePosition::internal(), &ct)
701            .map_err(Error::IllFormed)?;
702        Ok(ct)
703    }
704
705    fn elab_defined<'c>(&'c mut self, dt: &ComponentType<'a>) -> Result<Defined<'a>, Error<'a>> {
706        match dt {
707            ComponentType::Defined(vt) => Ok(Defined::Value(self.elab_defined_value(vt)?)),
708            ComponentType::Func(ft) => Ok(Defined::Func(self.elab_func(ft)?)),
709            ComponentType::Component(cds) => Ok(Defined::Component(self.elab_component(cds)?)),
710            ComponentType::Instance(ids) => Ok(Defined::Instance(self.elab_instance(ids)?)),
711            ComponentType::Resource { dtor, .. } => {
712                let rid = ResourceId {
713                    id: self.rtypes.len() as u32,
714                };
715                self.rtypes.push(Resource { _dtor: *dtor });
716                Ok(Defined::Handleable(Handleable::Resource(rid)))
717            }
718        }
719    }
720}