Skip to content

Commit

Permalink
Flesh out more text support for GC types in components (#1813)
Browse files Browse the repository at this point in the history
This commit builds on the work of #1764 to support the text format for
GC types in components more than before. This notably bring support for:

* `(sub ...)` types in components and module types
* `(rec ...)` groups in components and module types
* types can refer to themselves like with core wasm

The main consequence of this work is that unlike most other `$foo`
identifiers in the component model the identifiers found in types will
not automatically inject outer aliases to refer to outer types. For
example this will not parse:

    (component $C
      (type $t (struct))
      (component
        (type (array (ref $t)))
      )
    )

The reason for this is that automatic injection of an outer alias
requires that types are resolved and then their names are registered.
The resolution process queues up aliases to inject which are accounted
for during registration when indices are assigned. Here though because
types can refer to themselves (or future types in `rec` groups) the
registration process has to happen first before resolution. This means
that if resolution were to inject more type indices then that would mess
up the indexes already assigned.

This is hopefully relatively minor in terms of how often this'll bite
someone. For now various changes have been made to the name resolution
pass of components to handle this and some tests have been added too for
both positive and negative situations.
  • Loading branch information
alexcrichton committed Sep 20, 2024
1 parent 3e54745 commit 90fd388
Show file tree
Hide file tree
Showing 17 changed files with 438 additions and 175 deletions.
84 changes: 17 additions & 67 deletions crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use wasm_encoder::{
ComponentDefinedTypeEncoder, ComponentExportSection, ComponentImportSection,
ComponentInstanceSection, ComponentNameSection, ComponentSection, ComponentSectionId,
ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, CoreTypeSection,
InstanceSection, NameMap, NestedComponentSection, RawSection, SubType,
InstanceSection, NameMap, NestedComponentSection, RawSection,
};

pub fn encode(component: &Component<'_>, options: &EncodeOptions) -> Vec<u8> {
Expand All @@ -33,6 +33,7 @@ fn encode_fields(
ComponentField::CoreModule(m) => e.encode_core_module(m, options),
ComponentField::CoreInstance(i) => e.encode_core_instance(i),
ComponentField::CoreType(t) => e.encode_core_type(t),
ComponentField::CoreRec(t) => e.encode_core_rec(t),
ComponentField::Component(c) => e.encode_component(c, options),
ComponentField::Instance(i) => e.encode_instance(i),
ComponentField::Alias(a) => e.encode_alias(a),
Expand All @@ -58,12 +59,7 @@ fn encode_fields(
fn encode_core_type(encoder: ComponentCoreTypeEncoder, ty: &CoreTypeDef) {
match ty {
CoreTypeDef::Def(def) => {
let sub_type = SubType {
is_final: true,
supertype_idx: None,
composite_type: def.to_composite_type(),
};
encoder.core().subtype(&sub_type);
encoder.core().subtype(&def.to_subtype());
}
CoreTypeDef::Module(t) => {
encoder.module(&t.into());
Expand Down Expand Up @@ -232,6 +228,17 @@ impl<'a> Encoder<'a> {
self.flush(Some(self.core_types.id()));
}

fn encode_core_rec(&mut self, ty: &core::Rec<'a>) {
for ty in ty.types.iter() {
self.core_type_names.push(get_name(&ty.id, &ty.name));
}
self.core_types
.ty()
.core()
.rec(ty.types.iter().map(|t| t.to_subtype()));
self.flush(Some(self.core_types.id()));
}

fn encode_component(&mut self, component: &NestedComponent<'a>, options: &EncodeOptions) {
self.component_names
.push(get_name(&component.id, &component.name));
Expand Down Expand Up @@ -555,66 +562,6 @@ impl Custom<'_> {
}
}

// TODO: move these core conversion functions to the core module
// once we update core encoding to use wasm-encoder.
impl From<core::ValType<'_>> for wasm_encoder::ValType {
fn from(ty: core::ValType) -> Self {
match ty {
core::ValType::I32 => Self::I32,
core::ValType::I64 => Self::I64,
core::ValType::F32 => Self::F32,
core::ValType::F64 => Self::F64,
core::ValType::V128 => Self::V128,
core::ValType::Ref(r) => Self::Ref(r.into()),
}
}
}

impl From<core::RefType<'_>> for wasm_encoder::RefType {
fn from(r: core::RefType<'_>) -> Self {
wasm_encoder::RefType {
nullable: r.nullable,
heap_type: r.heap.into(),
}
}
}

impl From<core::HeapType<'_>> for wasm_encoder::HeapType {
fn from(r: core::HeapType<'_>) -> Self {
use wasm_encoder::AbstractHeapType::*;
match r {
core::HeapType::Abstract { shared, ty } => {
let ty = match ty {
core::AbstractHeapType::Func => Func,
core::AbstractHeapType::Extern => Extern,
core::AbstractHeapType::Exn => Exn,
core::AbstractHeapType::NoExn => NoExn,
core::AbstractHeapType::Any => Any,
core::AbstractHeapType::Eq => Eq,
core::AbstractHeapType::Struct => Struct,
core::AbstractHeapType::Array => Array,
core::AbstractHeapType::NoFunc => NoFunc,
core::AbstractHeapType::NoExtern => NoExtern,
core::AbstractHeapType::None => None,
core::AbstractHeapType::I31 => I31,
};
Self::Abstract { shared, ty }
}
core::HeapType::Concrete(Index::Num(i, _)) => Self::Concrete(i),
core::HeapType::Concrete(_) => panic!("unresolved index"),
}
}
}

impl<T: std::fmt::Debug> From<&core::TypeUse<'_, T>> for u32 {
fn from(u: &core::TypeUse<'_, T>) -> Self {
match &u.index {
Some(i) => (*i).into(),
None => unreachable!("unresolved type use in encoding: {:?}", u),
}
}
}

impl From<&CoreInstantiationArgKind<'_>> for wasm_encoder::ModuleArg {
fn from(kind: &CoreInstantiationArgKind) -> Self {
match kind {
Expand Down Expand Up @@ -807,6 +754,9 @@ impl From<&ModuleType<'_>> for wasm_encoder::ModuleType {
ModuleTypeDecl::Type(t) => {
encoded.ty().subtype(&t.to_subtype());
}
ModuleTypeDecl::Rec(rec) => {
encoded.ty().rec(rec.types.iter().map(|t| t.to_subtype()));
}
ModuleTypeDecl::Alias(a) => match &a.target {
AliasTarget::Outer {
outer,
Expand Down
7 changes: 6 additions & 1 deletion crates/wast/src/component/component.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::annotation;
use crate::component::*;
use crate::core::Producers;
use crate::core::{self, Producers};
use crate::kw;
use crate::parser::{Parse, Parser, Result};
use crate::token::Index;
Expand Down Expand Up @@ -146,6 +146,7 @@ pub enum ComponentField<'a> {
CoreModule(CoreModule<'a>),
CoreInstance(CoreInstance<'a>),
CoreType(CoreType<'a>),
CoreRec(core::Rec<'a>),
Component(NestedComponent<'a>),
Instance(Instance<'a>),
Alias(Alias<'a>),
Expand Down Expand Up @@ -185,6 +186,10 @@ impl<'a> Parse<'a> for ComponentField<'a> {
if parser.peek2::<kw::func>()? {
return Ok(Self::CoreFunc(parser.parse()?));
}
if parser.peek2::<kw::rec>()? {
parser.parse::<kw::core>()?;
return Ok(Self::CoreRec(parser.parse()?));
}
} else {
if parser.peek::<kw::component>()? {
return Ok(Self::Component(parser.parse()?));
Expand Down
4 changes: 2 additions & 2 deletions crates/wast/src/component/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl<'a> Expander<'a> {
self.expand_core_type(t);
None
}
ComponentField::CoreRec(_) => None,
ComponentField::Component(c) => self.expand_nested_component(c),
ComponentField::Instance(i) => self.expand_instance(i),
ComponentField::Type(t) => {
Expand Down Expand Up @@ -452,6 +453,7 @@ impl<'a> Expander<'a> {
core::InnerTypeKind::Struct(_) => {}
core::InnerTypeKind::Array(_) => {}
},
ModuleTypeDecl::Rec(_) => {}
ModuleTypeDecl::Alias(_) => {}
ModuleTypeDecl::Import(ty) => {
expand_sig(&mut ty.item, &mut to_prepend, &mut func_type_to_idx);
Expand Down Expand Up @@ -497,8 +499,6 @@ impl<'a> Expander<'a> {
// `shared` function must use an explicit type index,
// e.g., `(func (type $ft))`.
def: key.to_def(item.span, /* shared = */ false),
parent: None,
final_type: None,
}));
let idx = Index::Id(id);
t.index = Some(idx);
Expand Down
Loading

0 comments on commit 90fd388

Please sign in to comment.