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            ExternalKind::FuncExact => panic!("core type exact functions are not supported"),
70        }
71    }
72
73    pub(super) fn sort_matches_ed<'a>(sort: Sort, ed: &ExternDesc<'a>) {
74        match (sort, ed) {
75            (Sort::Core(CoreSort::Module), ExternDesc::CoreModule(_)) => (),
76            (Sort::Func, ExternDesc::Func(_)) => (),
77            (Sort::Type, ExternDesc::Type(_)) => (),
78            (Sort::Instance, ExternDesc::Instance(_)) => (),
79            (Sort::Component, ExternDesc::Component(_)) => (),
80            _ => panic!("sort does not match extern descriptor"),
81        }
82    }
83
84    pub(super) fn component_external_kind(k: ComponentExternalKind) -> Sort {
85        match k {
86            ComponentExternalKind::Module => Sort::Core(CoreSort::Module),
87            ComponentExternalKind::Func => Sort::Func,
88            ComponentExternalKind::Value => Sort::Value,
89            ComponentExternalKind::Type => Sort::Type,
90            ComponentExternalKind::Instance => Sort::Instance,
91            ComponentExternalKind::Component => Sort::Component,
92        }
93    }
94}
95use basic_conversions::*;
96
97#[derive(Debug)]
98#[allow(dead_code)]
99/// Elaboration-specific errors
100pub enum Error<'a> {
101    /// Innerizing an outer alias failed; this usually means that the
102    /// outer alias refers to a resource type or something like that.
103    InvalidOuterAlias(substitute::InnerizeError),
104    /// Innerizing an outer alias resulted in an ill-formed type; this
105    /// often also means that the outer alias refers to a resource
106    /// type or similar.
107    IllFormedOuterAlias(wf::Error<'a>),
108    /// The component type declarator should never have a resource
109    /// type in it, even though this is allowed by the grammar, since
110    /// there is no export (or instantiation) to generatively give it
111    /// identity.
112    ResourceInDeclarator,
113    /// A the typeidx inside an own/borrow handle should always point
114    /// to a resource type (either a bare resource, or, more usually,
115    /// an imported/exported type variable that is bounded by `(sub
116    /// resource)`.
117    HandleToNonResource,
118    /// Complex valtypes are allowed to use indirect type indices to
119    /// refer to another type, but the type index space is also used
120    /// for instance types, bare resource types, etc.  A malformed
121    /// complex value type which refers to a non-value type will
122    /// result in this error.
123    ValTypeRefToNonVal(Defined<'a>),
124    /// The finalisation/closing of a component or instance type
125    /// failed. This usually means that an exported type is referring
126    /// to a non-exported type variable or something along those
127    /// lines, which makes it impossible for the exported type to be
128    /// lifted out of the context.
129    ClosingError(substitute::ClosingError),
130    /// A finished component or instance type was ill-formed
131    IllFormed(wf::Error<'a>),
132}
133impl<'a> From<substitute::ClosingError> for Error<'a> {
134    fn from(e: substitute::ClosingError) -> Error<'a> {
135        Error::ClosingError(e)
136    }
137}
138
139/// # Elaboration
140///
141/// Most of this is a very direct translation of the specification
142/// (section 3.4 Type Elaboration).
143impl<'p, 'a> Ctx<'p, 'a> {
144    pub fn elab_component<'c>(
145        &'c mut self,
146        decls: &[ComponentTypeDeclaration<'a>],
147    ) -> Result<Component<'a>, Error<'a>> {
148        let mut ctx = Ctx::new(Some(self), false);
149        let mut imports = Vec::new();
150        let mut exports = Vec::new();
151        for decl in decls {
152            let (import, export) = ctx.elab_component_decl(decl)?;
153            if let Some(import) = import {
154                imports.push(import);
155            }
156            if let Some(export) = export {
157                exports.push(export);
158            }
159        }
160        ctx.finish_component(&imports, &exports)
161    }
162
163    fn elab_core_module_decl<'c>(
164        &'c mut self,
165        decl: &ModuleTypeDeclaration<'a>,
166    ) -> (Option<wasmparser::Import<'a>>, Option<CoreExportDecl<'a>>) {
167        match decl {
168            ModuleTypeDeclaration::Import(i) => (Some(*i), None),
169            ModuleTypeDeclaration::Type(rg) => {
170                let ct = self.elab_core_type_rec(rg);
171                self.core.types.push(ct);
172                (None, None)
173            }
174            ModuleTypeDeclaration::OuterAlias {
175                kind: OuterAliasKind::Type,
176                count,
177                index,
178            } => {
179                let ct = self.parents().nth(*count as usize).unwrap().core.types[*index as usize]
180                    .clone();
181                self.core.types.push(ct);
182                (None, None)
183            }
184            ModuleTypeDeclaration::Export { name, ty } => (
185                None,
186                Some(CoreExportDecl {
187                    name: Name { name },
188                    desc: match ty {
189                        TypeRef::Func(n) => match &self.core.types[*n as usize] {
190                            CoreDefined::Func(ft) => CoreExternDesc::Func(ft.clone()),
191                            _ => panic!(
192                                "internal invariant violation: WasmParser function TypeRef refers to non-function"
193                            ),
194                        },
195                        TypeRef::Table(tt) => CoreExternDesc::Table(*tt),
196                        TypeRef::Memory(mt) => CoreExternDesc::Memory(*mt),
197                        TypeRef::Global(gt) => CoreExternDesc::Global(*gt),
198                        TypeRef::Tag(_) => panic!("core type tags are not supported"),
199                        TypeRef::FuncExact(_) => {
200                            panic!("core type exact functions are not supported")
201                        }
202                    },
203                }),
204            ),
205        }
206    }
207
208    fn elab_core_module<'c>(&'c mut self, decls: &[ModuleTypeDeclaration<'a>]) -> CoreModule<'a> {
209        let mut ctx = Ctx::new(Some(self), false);
210        let mut imports = Vec::new();
211        let mut exports = Vec::new();
212        for decl in decls {
213            let (import, export) = ctx.elab_core_module_decl(decl);
214            if let Some(import) = import {
215                imports.push(import)
216            }
217            if let Some(export) = export {
218                exports.push(export)
219            }
220        }
221        CoreModule {
222            _imports: imports,
223            _exports: exports,
224        }
225    }
226
227    fn elab_core_type_rec<'c>(&'c mut self, rg: &wasmparser::RecGroup) -> CoreDefined<'a> {
228        match &rg.types().nth(0).unwrap().composite_type.inner {
229            CompositeInnerType::Func(ft) => CoreDefined::Func(ft.clone()),
230            _ => panic!("GC core types are not presently supported"),
231        }
232    }
233
234    fn elab_core_type<'c>(&'c mut self, ct: &wasmparser::CoreType<'a>) -> CoreDefined<'a> {
235        match ct {
236            CoreType::Rec(rg) => self.elab_core_type_rec(rg),
237            CoreType::Module(ds) => CoreDefined::Module(self.elab_core_module(ds)),
238        }
239    }
240
241    /// This tries to handle pretty much everything involved in alias
242    /// resolution and well-formedness checking. Since both core and
243    /// component aliases are largely similar, it can handle both and
244    /// has to return a union of core/component extern descriptors
245    /// that does not exist in the spec.
246    fn resolve_alias<'c>(
247        &'c mut self,
248        alias: &ComponentAlias<'a>,
249    ) -> Result<CoreOrComponentExternDesc<'a>, Error<'a>> {
250        match alias {
251            ComponentAlias::InstanceExport {
252                kind,
253                instance_index,
254                name,
255            } => {
256                let it = &self.instances[*instance_index as usize];
257                let ed = &it
258                    .exports
259                    .iter()
260                    .find(|e| e.kebab_name == *name)
261                    .unwrap()
262                    .desc;
263                let sort = component_external_kind(*kind);
264                sort_matches_ed(sort, ed);
265                Ok(CoreOrComponentExternDesc::Component(ed.clone()))
266            }
267            ComponentAlias::CoreInstanceExport {
268                kind,
269                instance_index,
270                name,
271            } => {
272                let it = &self.core.instances[*instance_index as usize];
273                let ed = &it
274                    .exports
275                    .iter()
276                    .find(|e| e.name.name == *name)
277                    .unwrap()
278                    .desc;
279                let sort = external_kind(*kind);
280                sort_matches_core_ed(sort, ed);
281                Ok(CoreOrComponentExternDesc::Core(ed.clone()))
282            }
283            ComponentAlias::Outer { kind, count, index } => {
284                if *kind != ComponentOuterAliasKind::Type {
285                    panic!("In types, only outer type aliases are allowed");
286                }
287                // Walk through each of the contexts between us and
288                // the targeted type, so that we can innerize each one
289                let mut ctxs = self.parents().take(*count as usize + 1).collect::<Vec<_>>();
290                ctxs.reverse();
291                let mut target_type = ctxs[0].types[*index as usize].clone();
292                let mut ob_crossed = false;
293                for ctxs_ in ctxs.windows(2) {
294                    ob_crossed |= ctxs_[1].outer_boundary;
295                    let sub = substitute::Innerize::new(ctxs_[0], ctxs_[1].outer_boundary);
296                    target_type = sub
297                        .defined(&target_type)
298                        .map_err(Error::InvalidOuterAlias)?;
299                }
300                if ob_crossed {
301                    self.wf_defined(wf::DefinedTypePosition::export(), &target_type)
302                        .map_err(Error::IllFormedOuterAlias)?;
303                }
304                Ok(CoreOrComponentExternDesc::Component(ExternDesc::Type(
305                    target_type,
306                )))
307            }
308        }
309    }
310
311    /// Add a core extern descriptor to the context: whatever it
312    /// describes is added to the relevant index space
313    fn add_core_ed<'c>(&'c mut self, ed: CoreExternDesc) {
314        match ed {
315            CoreExternDesc::Func(ft) => self.core.funcs.push(ft),
316            CoreExternDesc::Table(tt) => self.core.tables.push(tt),
317            CoreExternDesc::Memory(mt) => self.core.mems.push(mt),
318            CoreExternDesc::Global(gt) => self.core.globals.push(gt),
319        }
320    }
321
322    /// Add an extern descriptor to the context: whatever it describes
323    /// is added to the relevant index space. Note that this does not
324    /// handle stripping the type variables off of an instance type
325    /// (since `ExternDesc::Instance` doesn't have them); that should
326    /// have been done earlier. See for example the export instance
327    /// declarator case below, which converts the bound variables on
328    /// the instance type to context evars, and fixes them up in the
329    /// instance type, before calling add_ed.
330    fn add_ed<'c>(&'c mut self, ed: &ExternDesc<'a>) {
331        match ed {
332            ExternDesc::CoreModule(cmd) => self.core.modules.push(cmd.clone()),
333            ExternDesc::Func(ft) => self.funcs.push(ft.clone()),
334            ExternDesc::Type(dt) => self.types.push(dt.clone()),
335            ExternDesc::Instance(it) => self.instances.push(it.clone()),
336            ExternDesc::Component(ct) => self.components.push(ct.clone()),
337        }
338    }
339
340    fn add_core_or_component_ed<'c>(&'c mut self, ed: CoreOrComponentExternDesc<'a>) {
341        match ed {
342            CoreOrComponentExternDesc::Core(ced) => self.add_core_ed(ced),
343            CoreOrComponentExternDesc::Component(ed) => self.add_ed(&ed),
344        }
345    }
346
347    fn elab_value<'c>(&'c mut self, ctr: &ComponentValType) -> Result<Value<'a>, Error<'a>> {
348        match ctr {
349            ComponentValType::Type(n) => match &self.types[*n as usize] {
350                Defined::Value(vt) => Ok(vt.clone()),
351                dt @ Defined::Handleable(Handleable::Var(tv)) => match self.resolve_tyvar(tv) {
352                    ResolvedTyvar::Definite(Defined::Value(vt)) => {
353                        Ok(Value::Var(Some(tv.clone()), Box::new(vt)))
354                    }
355                    _ => Err(Error::ValTypeRefToNonVal(dt.clone())),
356                },
357                dt => Err(Error::ValTypeRefToNonVal(dt.clone())),
358            },
359            ComponentValType::Primitive(pt) => Ok(match pt {
360                PrimitiveValType::Bool => Value::Bool,
361                PrimitiveValType::S8 => Value::S(IntWidth::I8),
362                PrimitiveValType::U8 => Value::U(IntWidth::I8),
363                PrimitiveValType::S16 => Value::S(IntWidth::I16),
364                PrimitiveValType::U16 => Value::U(IntWidth::I16),
365                PrimitiveValType::S32 => Value::S(IntWidth::I32),
366                PrimitiveValType::U32 => Value::U(IntWidth::I32),
367                PrimitiveValType::S64 => Value::S(IntWidth::I64),
368                PrimitiveValType::U64 => Value::U(IntWidth::I64),
369                PrimitiveValType::F32 => Value::F(FloatWidth::F32),
370                PrimitiveValType::F64 => Value::F(FloatWidth::F64),
371                PrimitiveValType::Char => Value::Char,
372                PrimitiveValType::String => Value::String,
373                PrimitiveValType::ErrorContext => panic!("async not yet supported"),
374            }),
375        }
376    }
377
378    fn elab_defined_value<'c>(
379        &'c mut self,
380        vt: &ComponentDefinedType<'a>,
381    ) -> Result<Value<'a>, Error<'a>> {
382        match vt {
383            ComponentDefinedType::Primitive(pvt) => {
384                self.elab_value(&ComponentValType::Primitive(*pvt))
385            }
386            ComponentDefinedType::Record(rfs) => {
387                let rfs = rfs
388                    .iter()
389                    .map(|(name, ty)| {
390                        Ok::<_, Error<'a>>(RecordField {
391                            name: Name { name },
392                            ty: self.elab_value(ty)?,
393                        })
394                    })
395                    .collect::<Result<Vec<_>, Error<'a>>>()?;
396                Ok(Value::Record(rfs))
397            }
398            ComponentDefinedType::Variant(vcs) => {
399                let vcs = vcs
400                    .iter()
401                    .map(|vc| {
402                        Ok(VariantCase {
403                            name: Name { name: vc.name },
404                            ty: vc.ty.as_ref().map(|ty| self.elab_value(ty)).transpose()?,
405                            refines: vc.refines,
406                        })
407                    })
408                    .collect::<Result<Vec<_>, Error<'a>>>()?;
409                Ok(Value::Variant(vcs))
410            }
411            ComponentDefinedType::List(vt) => Ok(Value::List(Box::new(self.elab_value(vt)?))),
412            ComponentDefinedType::Tuple(vts) => Ok(Value::Tuple(
413                vts.iter()
414                    .map(|vt| self.elab_value(vt))
415                    .collect::<Result<Vec<_>, Error<'a>>>()?,
416            )),
417            ComponentDefinedType::Flags(ns) => {
418                Ok(Value::Flags(ns.iter().map(|n| Name { name: n }).collect()))
419            }
420            ComponentDefinedType::Enum(ns) => {
421                Ok(Value::Enum(ns.iter().map(|n| Name { name: n }).collect()))
422            }
423            ComponentDefinedType::Option(vt) => Ok(Value::Option(Box::new(self.elab_value(vt)?))),
424            ComponentDefinedType::Result { ok, err } => Ok(Value::Result(
425                Box::new(ok.map(|ok| self.elab_value(&ok)).transpose()?),
426                Box::new(err.map(|err| self.elab_value(&err)).transpose()?),
427            )),
428            ComponentDefinedType::Own(n) => match &self.types[*n as usize] {
429                Defined::Handleable(h) => Ok(Value::Own(h.clone())),
430                _ => Err(Error::HandleToNonResource),
431            },
432            ComponentDefinedType::Borrow(n) => match &self.types[*n as usize] {
433                Defined::Handleable(h) => Ok(Value::Borrow(h.clone())),
434                _ => Err(Error::HandleToNonResource),
435            },
436            ComponentDefinedType::FixedSizeList(vt, size) => {
437                Ok(Value::FixList(Box::new(self.elab_value(vt)?), *size))
438            }
439            ComponentDefinedType::Future(_) | ComponentDefinedType::Stream(_) => {
440                panic!("async not yet supported")
441            }
442        }
443    }
444
445    fn elab_func<'c>(&'c mut self, ft: &ComponentFuncType<'a>) -> Result<Func<'a>, Error<'a>> {
446        Ok(Func {
447            params: ft
448                .params
449                .iter()
450                .map(|(n, vt)| {
451                    Ok(Param {
452                        name: Name { name: n },
453                        ty: self.elab_value(vt)?,
454                    })
455                })
456                .collect::<Result<Vec<_>, Error<'a>>>()?,
457            result: ft
458                .result
459                .as_ref()
460                .map(|vt| self.elab_value(vt))
461                .transpose()?,
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}