hyperlight_component_util/
elaborate.rs

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