Skip to main content

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