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, ComponentFuncResult, ComponentFuncType,
28    ComponentOuterAliasKind, ComponentType, ComponentTypeDeclaration, ComponentTypeRef,
29    ComponentValType, CompositeInnerType, CoreType, InstanceTypeDeclaration, ModuleTypeDeclaration,
30    OuterAliasKind, PrimitiveValType, TypeBounds, TypeRef,
31};
32
33use crate::etypes::{
34    self, 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            }),
370        }
371    }
372
373    fn elab_defined_value<'c>(
374        &'c mut self,
375        vt: &ComponentDefinedType<'a>,
376    ) -> Result<Value<'a>, Error<'a>> {
377        match vt {
378            ComponentDefinedType::Primitive(pvt) => {
379                self.elab_value(&ComponentValType::Primitive(*pvt))
380            }
381            ComponentDefinedType::Record(rfs) => {
382                let rfs = rfs
383                    .iter()
384                    .map(|(name, ty)| {
385                        Ok::<_, Error<'a>>(RecordField {
386                            name: Name { name },
387                            ty: self.elab_value(ty)?,
388                        })
389                    })
390                    .collect::<Result<Vec<_>, Error<'a>>>()?;
391                Ok(Value::Record(rfs))
392            }
393            ComponentDefinedType::Variant(vcs) => {
394                let vcs = vcs
395                    .iter()
396                    .map(|vc| {
397                        Ok(VariantCase {
398                            name: Name { name: vc.name },
399                            ty: vc.ty.as_ref().map(|ty| self.elab_value(ty)).transpose()?,
400                            refines: vc.refines,
401                        })
402                    })
403                    .collect::<Result<Vec<_>, Error<'a>>>()?;
404                Ok(Value::Variant(vcs))
405            }
406            ComponentDefinedType::List(vt) => Ok(Value::List(Box::new(self.elab_value(vt)?))),
407            ComponentDefinedType::Tuple(vts) => Ok(Value::Tuple(
408                vts.iter()
409                    .map(|vt| self.elab_value(vt))
410                    .collect::<Result<Vec<_>, Error<'a>>>()?,
411            )),
412            ComponentDefinedType::Flags(ns) => {
413                Ok(Value::Flags(ns.iter().map(|n| Name { name: n }).collect()))
414            }
415            ComponentDefinedType::Enum(ns) => {
416                Ok(Value::Enum(ns.iter().map(|n| Name { name: n }).collect()))
417            }
418            ComponentDefinedType::Option(vt) => Ok(Value::Option(Box::new(self.elab_value(vt)?))),
419            ComponentDefinedType::Result { ok, err } => Ok(Value::Result(
420                Box::new(ok.map(|ok| self.elab_value(&ok)).transpose()?),
421                Box::new(err.map(|err| self.elab_value(&err)).transpose()?),
422            )),
423            ComponentDefinedType::Own(n) => match &self.types[*n as usize] {
424                Defined::Handleable(h) => Ok(Value::Own(h.clone())),
425                _ => Err(Error::HandleToNonResource),
426            },
427            ComponentDefinedType::Borrow(n) => match &self.types[*n as usize] {
428                Defined::Handleable(h) => Ok(Value::Borrow(h.clone())),
429                _ => Err(Error::HandleToNonResource),
430            },
431            ComponentDefinedType::Future(_)
432            | ComponentDefinedType::Stream(_)
433            | ComponentDefinedType::ErrorContext => panic!("async not yet supported"),
434        }
435    }
436
437    fn elab_func<'c>(&'c mut self, ft: &ComponentFuncType<'a>) -> Result<Func<'a>, Error<'a>> {
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: match &ft.results {
450                ComponentFuncResult::Unnamed(vt) => etypes::Result::Unnamed(self.elab_value(vt)?),
451                ComponentFuncResult::Named(rs) => etypes::Result::Named(
452                    rs.iter()
453                        .map(|(n, vt)| {
454                            Ok(Param {
455                                name: Name { name: n },
456                                ty: self.elab_value(vt)?,
457                            })
458                        })
459                        .collect::<Result<Vec<_>, Error<'a>>>()?,
460                ),
461            },
462        })
463    }
464
465    /// Elaborate an extern descriptor. This returns any evars that
466    /// are implied by the descriptor separately, to simplify
467    /// converting them to context e/u vars, which is usually what you
468    /// want to do.
469    fn elab_extern_desc<'c>(
470        &'c mut self,
471        ed: &ComponentTypeRef,
472    ) -> Result<(Vec<BoundedTyvar<'a>>, ExternDesc<'a>), Error<'a>> {
473        match ed {
474            ComponentTypeRef::Module(i) => match &self.core.types[*i as usize] {
475                CoreDefined::Module(mt) => Ok((vec![], ExternDesc::CoreModule(mt.clone()))),
476                _ => {
477                    panic!("internal invariant violation: bad sort for ComponentTypeRef to Module")
478                }
479            },
480            ComponentTypeRef::Func(i) => match &self.types[*i as usize] {
481                Defined::Func(ft) => Ok((vec![], ExternDesc::Func(ft.clone()))),
482                _ => panic!("internal invariant violation: bad sort for ComponentTypeRef to Func"),
483            },
484            ComponentTypeRef::Value(_) => panic!("First-class values are not yet supported"),
485            ComponentTypeRef::Type(tb) => {
486                let bound = match tb {
487                    TypeBounds::Eq(i) => TypeBound::Eq(self.types[*i as usize].clone()),
488                    TypeBounds::SubResource => TypeBound::SubResource,
489                };
490                let dt = Defined::Handleable(Handleable::Var(Tyvar::Bound(0)));
491                Ok((vec![BoundedTyvar::new(bound)], ExternDesc::Type(dt)))
492            }
493            ComponentTypeRef::Instance(i) => match &self.types[*i as usize] {
494                Defined::Instance(qit) => Ok((
495                    qit.evars.clone(),
496                    ExternDesc::Instance(qit.unqualified.clone()),
497                )),
498                _ => panic!(
499                    "internal invariant violation: bad sort for ComponentTypeRef to Instance"
500                ),
501            },
502            ComponentTypeRef::Component(i) => match &self.types[*i as usize] {
503                Defined::Component(ct) => Ok((vec![], ExternDesc::Component(ct.clone()))),
504                _ => panic!(
505                    "internal invariant violation: bad sort for ComponentTypeRef to Component"
506                ),
507            },
508        }
509    }
510
511    fn elab_instance_decl<'c>(
512        &'c mut self,
513        decl: &InstanceTypeDeclaration<'a>,
514    ) -> Result<Option<ExternDecl<'a>>, Error<'a>> {
515        match decl {
516            InstanceTypeDeclaration::CoreType(ct) => {
517                let ct = self.elab_core_type(ct);
518                self.core.types.push(ct);
519                Ok(None)
520            }
521            InstanceTypeDeclaration::Type(t) => {
522                let t = self.elab_defined(t)?;
523                if let Defined::Handleable(_) = t {
524                    return Err(Error::ResourceInDeclarator);
525                }
526                self.types.push(t);
527                Ok(None)
528            }
529            InstanceTypeDeclaration::Alias(a) => {
530                let ed = self.resolve_alias(a)?;
531                self.add_core_or_component_ed(ed);
532                Ok(None)
533            }
534            InstanceTypeDeclaration::Export { name, ty } => {
535                let (vs, ed) = self.elab_extern_desc(ty)?;
536                let sub = self.bound_to_evars(Some(name.0), &vs);
537                let ed = sub.extern_desc(&ed).not_void();
538                self.add_ed(&ed);
539                Ok(Some(ExternDecl {
540                    kebab_name: name.0,
541                    desc: ed,
542                }))
543            }
544        }
545    }
546
547    fn elab_instance<'c>(
548        &'c mut self,
549        decls: &[InstanceTypeDeclaration<'a>],
550    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
551        let mut ctx = Ctx::new(Some(self), false);
552        let mut exports = Vec::new();
553        for decl in decls {
554            let export = ctx.elab_instance_decl(decl)?;
555            if let Some(export) = export {
556                exports.push(export);
557            }
558        }
559        ctx.finish_instance(&exports)
560    }
561
562    /// Convert instance variables in the context into bound variables
563    /// in the type. This is pulled out separately from raising the
564    /// resulting type so that it can be shared between
565    /// [`Ctx::finish_instance`] and [`Ctx::finish_component`], which
566    /// have different requirements in that respect.
567    fn finish_instance_evars(
568        self,
569        exports: &[ExternDecl<'a>],
570    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
571        let mut evars = Vec::new();
572        let mut sub = substitute::Closing::new(false);
573        for (bound, _) in self.evars {
574            let bound = sub.bounded_tyvar(&bound)?;
575            evars.push(bound);
576            sub.next_e();
577        }
578        let unqualified = sub.instance(&Instance {
579            exports: exports.to_vec(),
580        })?;
581        Ok(QualifiedInstance { evars, unqualified })
582    }
583
584    /// The equivalent of the \oplus in the spec.  This has to deal
585    /// with more bookkeeping because of our variable representation:
586    /// the free variables in the exports need to be converted to
587    /// bound variables, and any free variables referring to upper
588    /// contexts need to have their parent/outer index reduced by one
589    /// to deal with this context ending.
590    fn finish_instance(
591        self,
592        exports: &[ExternDecl<'a>],
593    ) -> Result<QualifiedInstance<'a>, Error<'a>> {
594        // When we do the well-formedness check in a minute, we need
595        // to use the parent ctx, because the closing substitution has
596        // already been applied.
597        let fallback_parent = Ctx::new(None, false);
598        let parent_ctx = self.parent.unwrap_or(&fallback_parent);
599
600        let qi = self.finish_instance_evars(exports)?;
601        let raise_u_sub = substitute::Closing::new(true);
602        let it = raise_u_sub.qualified_instance(&qi)?;
603        parent_ctx
604            .wf_qualified_instance(wf::DefinedTypePosition::internal(), &it)
605            .map_err(Error::IllFormed)?;
606        Ok(it)
607    }
608
609    fn elab_component_decl<'c>(
610        &'c mut self,
611        decl: &ComponentTypeDeclaration<'a>,
612    ) -> Result<(Option<ExternDecl<'a>>, Option<ExternDecl<'a>>), Error<'a>> {
613        match decl {
614            ComponentTypeDeclaration::CoreType(ct) => {
615                let ct = self.elab_core_type(ct);
616                self.core.types.push(ct);
617                Ok((None, None))
618            }
619            ComponentTypeDeclaration::Type(t) => {
620                let t = self.elab_defined(t)?;
621                if let Defined::Handleable(_) = t {
622                    return Err(Error::ResourceInDeclarator);
623                }
624                self.types.push(t);
625                Ok((None, None))
626            }
627            ComponentTypeDeclaration::Alias(a) => {
628                let ed = self.resolve_alias(a)?;
629                self.add_core_or_component_ed(ed);
630                Ok((None, None))
631            }
632            ComponentTypeDeclaration::Export { name, ty, .. } => {
633                let (vs, ed) = self.elab_extern_desc(ty)?;
634                let sub = self.bound_to_evars(Some(name.0), &vs);
635                let ed = sub.extern_desc(&ed).not_void();
636                self.add_ed(&ed);
637                Ok((
638                    None,
639                    Some(ExternDecl {
640                        kebab_name: name.0,
641                        desc: ed,
642                    }),
643                ))
644            }
645            ComponentTypeDeclaration::Import(i) => {
646                let (vs, ed) = self.elab_extern_desc(&i.ty)?;
647                let sub = self.bound_to_uvars(Some(i.name.0), &vs, true);
648                let ed = sub.extern_desc(&ed).not_void();
649                self.add_ed(&ed);
650                Ok((
651                    Some(ExternDecl {
652                        kebab_name: i.name.0,
653                        desc: ed,
654                    }),
655                    None,
656                ))
657            }
658        }
659    }
660
661    /// Similar to [`Ctx::finish_instance`], but for components; this
662    /// has to cover uvars as well as evars.
663    fn finish_component(
664        self,
665        imports: &[ExternDecl<'a>],
666        exports: &[ExternDecl<'a>],
667    ) -> Result<Component<'a>, Error<'a>> {
668        // When we do the well-formedness check in a minute, we need
669        // to use the parent ctx, because the closing substitution has
670        // already been applied.
671        let fallback_parent = Ctx::new(None, false);
672        let parent_ctx = self.parent.unwrap_or(&fallback_parent);
673
674        let mut uvars = Vec::new();
675        let mut sub = substitute::Closing::new(true);
676        for (bound, imported) in &self.uvars {
677            let bound = sub.bounded_tyvar(bound)?;
678            uvars.push(bound);
679            sub.next_u(*imported);
680        }
681        let imports = imports
682            .iter()
683            .map(|ed| sub.extern_decl(ed).map_err(Into::into))
684            .collect::<Result<Vec<ExternDecl<'a>>, Error<'a>>>()?;
685        let instance = sub.qualified_instance(&self.finish_instance_evars(exports)?)?;
686        let ct = Component {
687            uvars,
688            imports,
689            instance,
690        };
691        parent_ctx
692            .wf_component(wf::DefinedTypePosition::internal(), &ct)
693            .map_err(Error::IllFormed)?;
694        Ok(ct)
695    }
696
697    fn elab_defined<'c>(&'c mut self, dt: &ComponentType<'a>) -> Result<Defined<'a>, Error<'a>> {
698        match dt {
699            ComponentType::Defined(vt) => Ok(Defined::Value(self.elab_defined_value(vt)?)),
700            ComponentType::Func(ft) => Ok(Defined::Func(self.elab_func(ft)?)),
701            ComponentType::Component(cds) => Ok(Defined::Component(self.elab_component(cds)?)),
702            ComponentType::Instance(ids) => Ok(Defined::Instance(self.elab_instance(ids)?)),
703            ComponentType::Resource { dtor, .. } => {
704                let rid = ResourceId {
705                    id: self.rtypes.len() as u32,
706                };
707                self.rtypes.push(Resource { _dtor: *dtor });
708                Ok(Defined::Handleable(Handleable::Resource(rid)))
709            }
710        }
711    }
712}