From ae1cf7ca4956d676ddcc4e9edb7d8781193cfe6b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 6 Oct 2025 15:27:28 -0700 Subject: [PATCH] Merge tests from wasm-tools and Wasmtime This commit merges tests from the wasm-tools and wasmtime repositories for the component model upstream into this repository itself. Everything should be passing in Wasmtime with `-Wexceptions` after bytecodealliance/wasmtime#11798 is merged. In terms of test suite organization AFAIK there's not precedent in the core wasm specification itself for importing tests from engines themselves. Given that I wanted to sort of chart out a new course for this which doesn't necessarily look exactly like "merge all the tests into one directory". To that end the changes here are: * New `tests/wasm-tools` and `tests/wasmtime` directories exist. * Tests are copied as-is into these folders from their upstream locations in `tests/cli/component-model` in wasm-tools and `tests/misc_testsuite/component-model` in Wasmtime. * Tests are omitted for component model features such as values and GC integration. Additionally no async tests are yet present (although some are present upstream). * Tests are kept segregated in case of a hypothetical future automatic synchronization where tests are pulled from Wasmtime directly into the spec here, for example. * Tests are not edited from their Wasmtime/wasm-tools equivalents which means they have "funky directives" at the top which are intended to only have meaning in the Wasmtime/wasm-tools repos. * In theory there could be new subdirectories such as `test/wasm-tools/async/*.wast` for proposals/extensions to the component model. I'd reorganize tests upstream for this if desired. Overall one thing I'm effectively proposing as part of this is to provide a "dumping ground" of per-repo tests which get dumped into one canonical location. The hope is that it makes it easier to contribute tests to the spec which means that the tests can rapidly grow over time. Quality of tests is intended to be enforced eventually by ensuring that at least one runtime (maybe a reference implementation) passes the tests, so not just anything could be added in theory. For now though my hope is to seed a test suite for the component model for some of the tricker cases especially related to resources as others become interested in implementing the component model. --- test/wasm-tools/adapt.wast | 287 +++ test/wasm-tools/alias.wast | 301 +++ test/wasm-tools/big.wast | 36 + test/wasm-tools/definedtypes.wast | 162 ++ test/wasm-tools/empty.wast | 4 + test/wasm-tools/example.wast | 17 + test/wasm-tools/export-ascription.wast | 44 + test/wasm-tools/export-introduces-alias.wast | 48 + test/wasm-tools/export.wast | 63 + test/wasm-tools/func.wast | 146 ++ test/wasm-tools/import.wast | 359 +++ test/wasm-tools/imports-exports.wast | 26 + test/wasm-tools/inline-exports.wast | 9 + test/wasm-tools/instance-type.wast | 234 ++ test/wasm-tools/instantiate.wast | 976 ++++++++ test/wasm-tools/invalid.wast | 34 + test/wasm-tools/link.wast | 14 + test/wasm-tools/lots-of-aliases.wast | 179 ++ test/wasm-tools/lower.wast | 17 + test/wasm-tools/memory64.wast | 54 + test/wasm-tools/module-link.wast | 98 + test/wasm-tools/more-flags.wast | 41 + test/wasm-tools/naming.wast | 130 ++ test/wasm-tools/nested-modules.wast | 50 + test/wasm-tools/resources.wast | 1195 ++++++++++ test/wasm-tools/tags.wast | 30 + test/wasm-tools/type-export-restrictions.wast | 504 +++++ test/wasm-tools/types.wast | 374 ++++ test/wasm-tools/very-nested.wast | 1954 +++++++++++++++++ test/wasm-tools/virtualize.wast | 119 + test/wasm-tools/wrong-order.wast | 11 + test/wasmtime/adapter.wast | 137 ++ test/wasmtime/aliasing.wast | 29 + test/wasmtime/fused.wast | 1359 ++++++++++++ test/wasmtime/import.wast | 20 + test/wasmtime/instance.wast | 327 +++ test/wasmtime/linking.wast | 18 + test/wasmtime/modules.wast | 479 ++++ test/wasmtime/nested.wast | 451 ++++ test/wasmtime/resources.wast | 1091 +++++++++ test/wasmtime/restrictions.wast | 22 + test/wasmtime/simple.wast | 42 + test/wasmtime/strings.wast | 110 + test/wasmtime/tags.wast | 14 + test/wasmtime/types.wast | 355 +++ 45 files changed, 11970 insertions(+) create mode 100644 test/wasm-tools/adapt.wast create mode 100644 test/wasm-tools/alias.wast create mode 100644 test/wasm-tools/big.wast create mode 100644 test/wasm-tools/definedtypes.wast create mode 100644 test/wasm-tools/empty.wast create mode 100644 test/wasm-tools/example.wast create mode 100644 test/wasm-tools/export-ascription.wast create mode 100644 test/wasm-tools/export-introduces-alias.wast create mode 100644 test/wasm-tools/export.wast create mode 100644 test/wasm-tools/func.wast create mode 100644 test/wasm-tools/import.wast create mode 100644 test/wasm-tools/imports-exports.wast create mode 100644 test/wasm-tools/inline-exports.wast create mode 100644 test/wasm-tools/instance-type.wast create mode 100644 test/wasm-tools/instantiate.wast create mode 100644 test/wasm-tools/invalid.wast create mode 100644 test/wasm-tools/link.wast create mode 100644 test/wasm-tools/lots-of-aliases.wast create mode 100644 test/wasm-tools/lower.wast create mode 100644 test/wasm-tools/memory64.wast create mode 100644 test/wasm-tools/module-link.wast create mode 100644 test/wasm-tools/more-flags.wast create mode 100644 test/wasm-tools/naming.wast create mode 100644 test/wasm-tools/nested-modules.wast create mode 100644 test/wasm-tools/resources.wast create mode 100644 test/wasm-tools/tags.wast create mode 100644 test/wasm-tools/type-export-restrictions.wast create mode 100644 test/wasm-tools/types.wast create mode 100644 test/wasm-tools/very-nested.wast create mode 100644 test/wasm-tools/virtualize.wast create mode 100644 test/wasm-tools/wrong-order.wast create mode 100644 test/wasmtime/adapter.wast create mode 100644 test/wasmtime/aliasing.wast create mode 100644 test/wasmtime/fused.wast create mode 100644 test/wasmtime/import.wast create mode 100644 test/wasmtime/instance.wast create mode 100644 test/wasmtime/linking.wast create mode 100644 test/wasmtime/modules.wast create mode 100644 test/wasmtime/nested.wast create mode 100644 test/wasmtime/resources.wast create mode 100644 test/wasmtime/restrictions.wast create mode 100644 test/wasmtime/simple.wast create mode 100644 test/wasmtime/strings.wast create mode 100644 test/wasmtime/tags.wast create mode 100644 test/wasmtime/types.wast diff --git a/test/wasm-tools/adapt.wast b/test/wasm-tools/adapt.wast new file mode 100644 index 00000000..8cc76f8f --- /dev/null +++ b/test/wasm-tools/adapt.wast @@ -0,0 +1,287 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "log" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + + (core module $my_module + (import "env" "log-utf8" (func $log_utf8 (param i32 i32))) + (import "env" "log-utf16" (func $log_utf16 (param i32 i32))) + (import "env" "log-compact-utf16" (func $log_compact_utf16 (param i32 i32))) + + (func (export "log-utf8") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf8 + ) + (func (export "log-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_utf16 + ) + (func (export "log-compact-utf16") (param i32 i32) + local.get 0 + local.get 1 + call $log_compact_utf16 + ) + ) + + (core instance $libc (instantiate $libc)) + + (alias core export $libc "canonical_abi_realloc" (core func $realloc)) + (alias core export $libc "memory" (core memory $memory)) + (core func $log_lower_utf8 (canon lower (func $log) string-encoding=utf8 (memory $memory) (realloc $realloc))) + (core func $log_lower_utf16 (canon lower (func $log) string-encoding=utf16 (memory $memory) (realloc $realloc))) + (core func $log_lower_compact_utf16 (canon lower (func $log) string-encoding=latin1+utf16 (memory $memory) (realloc $realloc))) + + (core instance $my_instance (instantiate $my_module + (with "libc" (instance $libc)) + (with "env" (instance + (export "log-utf8" (func $log_lower_utf8)) + (export "log-utf16" (func $log_lower_utf16)) + (export "log-compact-utf16" (func $log_lower_compact_utf16)) + )) + )) + + (func (export "log1") (param "msg" string) + (canon lift + (core func $my_instance "log-utf8") + string-encoding=utf8 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log2") (param "msg" string) + (canon lift + (core func $my_instance "log-utf16") + string-encoding=utf16 + (memory $memory) + (realloc $realloc) + ) + ) + (func (export "log3") (param "msg" string) + (canon lift + (core func $my_instance "log-compact-utf16") + string-encoding=latin1+utf16 + (memory $memory) + (realloc $realloc) + ) + ) +) + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) + ) + "canonical encoding option `utf8` conflicts with option `utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf8` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) + ) + "canonical encoding option `utf16` conflicts with option `latin1-utf16`") + +(assert_invalid + (component + (import "i" (func $f)) + (core func (canon lower (func $f) (memory 0))) + ) + "memory index out of bounds") + +(assert_invalid + (component + (import "i" (func $f)) + (core module $m (memory (export "memory") 1)) + (core instance $i (instantiate $m)) + (core func (canon lower (func $f) (memory $i "memory") (memory $i "memory"))) + ) + "`memory` is specified more than once") + +(assert_invalid + (component + (core module $m + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) (canon lift (core func $i "f"))) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + ) + ) + ) + "canonical option `realloc` is required") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` is specified more than once") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r")) + ) + (core instance $i (instantiate $m)) + (func (param "p1" (list u8)) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + ) + ) + ) + "canonical option `realloc` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p")) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` uses a core function with an incorrect signature") + +(assert_invalid + (component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` is specified more than once") + +(assert_invalid + (component + (import "i" (func $f (param "p1" string))) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (core func + (canon lower (func $f) + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) + ) + "canonical option `post-return` cannot be specified for lowerings") + +(component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32) unreachable) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory $i "m") + (realloc (func $i "r")) + (post-return (func $i "p")) + ) + ) +) + +(assert_malformed + (component quote + "(core module $m (func (export \"\")))" + "(core instance $i (instantiate $m))" + "(core func (canon lower (func $i \"\")))" + ) + "unknown instance: failed to find name `$i`") + +(assert_invalid + (component + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered parameter types `[]` do not match parameter types `[I32]`") + +(assert_invalid + (component + (core module $m (func (export "foo") (result i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) + ) + "lowered result types `[]` do not match result types `[I32]`") + +(assert_invalid + (component + (type $f string) + (core module $m (func (export "foo"))) + (core instance $i (instantiate $m)) + (func (export "foo") (type $f) (canon lift (core func $i "foo"))) + ) + "not a function type") + +(assert_malformed + (component quote + "(import \"a\" (func $f))" + "(func (export \"foo\") (canon lift (core func $f)))" + ) + "unknown core func: failed to find name `$f`") diff --git a/test/wasm-tools/alias.wast b/test/wasm-tools/alias.wast new file mode 100644 index 00000000..dd9d1b37 --- /dev/null +++ b/test/wasm-tools/alias.wast @@ -0,0 +1,301 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "i" (instance $i + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (export "run" (func $i "f1")) + ) +) + +(component + (component + (import "i" (component $c + (export "f1" (func)) + (export "f2" (func (param "p1" string))) + )) + (instance $i (instantiate $c)) + (export "run" (func $i "f1")) + ) +) + +(component definition + (import "i" (core module $m + (export "f1" (func $f1)) + (export "f2" (func $f2 (param i32))) + )) + (core instance $i (instantiate $m)) + + (core module $m2 (import "" "" (func))) + + (core instance (instantiate $m2 (with "" (instance (export "" (func $i "f1")))))) +) + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $mem)) + (export "table" (table $tbl)) + (export "func" (func $func)) + (export "global" (global $global)) + (export "global mut" (global $global_mut)) + )))) +) + +(component + (component + (import "a" (instance $i + (export "a" (func)) + (export "b" (core module)) + (export "c" (instance)) + )) + (export "b" (func $i "a")) + (export "c" (core module $i "b")) + (export "d" (instance $i "c")) + ) +) + + +(component definition + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + + (import "b" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance $libc (instantiate $libc)) + (core instance (instantiate $needs_libc (with "" (instance + (export "memory" (memory $libc "memory")) + (export "table" (table $libc "table")) + (export "func" (func $libc "func")) + (export "global" (global $libc "global")) + (export "global mut" (global $libc "global mut")) + )))) +) + +(assert_invalid + (component + (import "a" (instance (export "a" (func)))) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (component + (component (export "a")) + ) + (instance (instantiate 0)) + (export "a" (core module 0 "a")) + ) + "export `a` for instance 0 is not a module") + +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (core module) + (core instance (instantiate 0)) + (alias core export 0 "a" (core func)) + ) + "core instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (component)) + (instance (instantiate 0)) + (alias export 0 "a" (func)) + ) + "instance 0 has no export named `a`") + +(assert_invalid + (component + (import "a" (core module $a (export "" (func)))) + (import "b" (core module $b (import "" "" (func (param i32))))) + + (core instance $a (instantiate $a)) + (core instance $b (instantiate $b (with "" (instance $a)))) + ) + "type mismatch") + +;; aliasing various items works + +(component $PARENT + (type $t (func (result string))) + (component + (import "a" (func (type $t))) + ) + (component + (alias outer $PARENT $t (type $my_type)) + (alias outer 0 $my_type (type $my_type_again)) + (import "a" (func (type $my_type_again))) + ) +) + +(component + (type $a (func (result string))) + (component + (type $b (func (result u32))) + (component + (type $c (func (result s32))) + + (component + (import "a" (func $a (type $a))) + (import "b" (func $b (type $b))) + (import "c" (func $c (type $c))) + + (import "d" (component $C + (import "a" (func (result string))) + (import "b" (func (result u32))) + (import "c" (func (result s32))) + )) + + (instance (instantiate $C + (with "a" (func $a)) + (with "b" (func $b)) + (with "c" (func $c)) + )) + ) + ) + ) +) + +;; multiple projections in alias sugar +(component + (component $a + (import "a" (instance $a + (export "a" (instance + (export "a" (instance + (export "a" (instance + (export "a" (func)) + )) + )) + )) + )) + + (import "b" (component $b (import "a" (func)))) + + (instance (instantiate $b + (with "a" (func $a "a" "a" "a" "a")) + )) + ) +) + +;; alias some constructs +(component + (component + (import "a" (instance $foo (export "v" (component)))) + (export "v" (component $foo "v")) + ) +) + +(component definition + (import "a" (instance $foo (export "v" (core module)))) + (export "v" (core module $foo "v")) +) + +(component $C + (core type $t (func)) + (component $C2 + (alias outer $C $t (core type $t2)) + (component + (alias outer $C $t (core type)) + (alias outer $C2 $t2 (core type)) + ) + ) +) + +(component $C + (core module $m) + (alias outer $C $m (core module $target)) + (export "v" (core module $target)) +) + +(component + (component $C + (component $m) + (alias outer $C $m (component $target)) + (export "v" (component $target)) + ) +) + +(assert_invalid + (component (alias outer 100 0 (core type))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core type))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (core module))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (core module))) + "index out of bounds") + +(assert_invalid + (component (alias outer 100 0 (component))) + "invalid outer alias count of 100") + +(assert_invalid + (component (alias outer 0 0 (component))) + "index out of bounds") + +(component definition + (import "a" (instance $i + (export "x" (core module)) + )) + ;; inline alias injection sugar works for module references + (core instance (instantiate (module $i "x"))) +) + +(component + (component + (import "a" (instance $i + (export "x" (component)) + )) + ;; inline alias injection sugar works for component references + (instance (instantiate (component $i "x"))) + ) +) diff --git a/test/wasm-tools/big.wast b/test/wasm-tools/big.wast new file mode 100644 index 00000000..770df0ab --- /dev/null +++ b/test/wasm-tools/big.wast @@ -0,0 +1,36 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "wasi-logging" (instance $logging + (export "log" (func (param "msg" string))) + )) + (import "libc" (core module $Libc + (export "memory" (memory 1)) + (export "realloc" (func (param i32 i32 i32 i32) (result i32))) + )) + (core instance $libc (instantiate $Libc)) + (core func $log (canon lower + (func $logging "log") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (core module $Main + (import "libc" "memory" (memory 1)) + (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) + (import "wasi-logging" "log" (func $log (param i32 i32))) + (func (export "run") (param i32 i32) (result i32) + (local.get 0) + (local.get 1) + (call $log) + (unreachable) + ) + ) + (core instance $main (instantiate $Main + (with "libc" (instance $libc)) + (with "wasi-logging" (instance (export "log" (func $log)))) + )) + (func $run (param "in" string) (result string) (canon lift + (core func $main "run") + (memory $libc "memory") (realloc (func $libc "realloc")) + )) + (export "run" (func $run)) +) diff --git a/test/wasm-tools/definedtypes.wast b/test/wasm-tools/definedtypes.wast new file mode 100644 index 00000000..989ebcf2 --- /dev/null +++ b/test/wasm-tools/definedtypes.wast @@ -0,0 +1,162 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component $C + (type $A1 bool) + (type $A2 u8) + (type $A3 s8) + (type $A4 u16) + (type $A5 s16) + (type $A6 u32) + (type $A7 s32) + (type $A8 u64) + (type $A9 s64) + (type $A10a f32) + (type $A11a f64) + (type $A10b float32) + (type $A11b float64) + (type $A12 char) + (type $A13 string) + + (type $A14b (record (field "x" (tuple char)))) + (type $A14c (record (field "x" $A1))) + + (type $A15a (variant (case "x"))) + (type $A15b (variant (case "x" $A1))) + (type $A15c (variant (case $x "x") (case $y "y" string (refines $x)) (case "z" string (refines $y)))) + (type $A15d (variant (case "x") (case "y" string (refines 0)) (case "z" string (refines 1)))) + + (type $A16a (list (tuple u8))) + (type $A16b (list $A3)) + + (type $A17a (tuple u8)) + (type $A17b (tuple $A4)) + + (type $A18b (flags "x")) + + (type $A19b (enum "x")) + + (type $A21a (option (tuple u32))) + (type $A21b (option $A6)) + + (type $A22a (result)) + (type $A22b (result $A7)) + (type $A22c (result (error $A8))) + (type $A22d (result $A9 (error $A10a))) +) + +(assert_malformed + (component quote + "(type $t (variant (case $x \"x\" string (refines $x))))" + ) + "variant case cannot refine itself" +) + +(assert_malformed + (component quote + "(type $t (variant (case \"x\" (refines $y)) (case $y \"y\" string)))" + ) + "unknown variant case" +) + +(assert_malformed + (component quote + "(type $t string)" + "(type $v (variant (case \"x\" $t (refines $z))))" + ) + "unknown variant case" +) + + +(assert_invalid + (component + (type $t string) + (type $v (variant (case "x" $t (refines 1)))) + ) + "variant case can only refine a previously defined case" +) + +(assert_invalid + (component + (type $t string) + (type $v (variant (case "x" $t) (case "y" u64 (refines 2)) (case "z" string))) + ) + "variant case can only refine a previously defined case" +) + +(assert_malformed + (component quote + "(type $t string)" + "(type $v (variant (case $x \"x\" $t) (case $x \"y\" $t)))" + ) + "duplicate variant case identifier" +) + +(assert_invalid + (component + (type $t (func)) + (type (func (param "t" $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (instance)) + (type (func (result $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (component)) + (type (option $t)) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component (type (option 0))) + "index out of bounds") +(assert_invalid + (component (type (list 0))) + "index out of bounds") +(assert_invalid + (component (type (record (field "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (variant (case "x" 0)))) + "index out of bounds") +(assert_invalid + (component (type (result 0 (error 1)))) + "index out of bounds") +(assert_invalid + (component (type (tuple 0))) + "index out of bounds") + +(assert_invalid + (component (type (record (field "a-B-c-D" string) (field "A-b-C-d" u8)))) + "record field name `A-b-C-d` conflicts with previous field name `a-B-c-D`") +(assert_invalid + (component (type (variant (case "x" s64) (case "x" s64)))) + "variant case name `x` conflicts with previous case name `x`") +(assert_invalid + (component (type (flags "x" "y" "X"))) + "flag name `X` conflicts with previous flag name `x`") +(assert_invalid + (component (type (enum "x" "y" "X"))) + "enum tag name `X` conflicts with previous tag name `x`") + +(assert_invalid + (component (type (record (field "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (variant (case "" s32)))) + "name cannot be empty") +(assert_invalid + (component (type (flags ""))) + "name cannot be empty") +(assert_invalid + (component (type (enum ""))) + "name cannot be empty") + +(assert_invalid + (component (type (variant))) + "variant type must have at least one case") diff --git a/test/wasm-tools/empty.wast b/test/wasm-tools/empty.wast new file mode 100644 index 00000000..7f22181b --- /dev/null +++ b/test/wasm-tools/empty.wast @@ -0,0 +1,4 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; The most minimal component. +(component) diff --git a/test/wasm-tools/example.wast b/test/wasm-tools/example.wast new file mode 100644 index 00000000..9ba429fe --- /dev/null +++ b/test/wasm-tools/example.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define the following component: + +(component + (component + (core module (func (export "one") (result i32) (i32.const 1))) + (core module (func (export "two") (result f32) (f32.const 2))) + ) + (core module (func (export "three") (result i64) (i64.const 3))) + (component + (component + (core module (func (export "four") (result f64) (f64.const 4))) + ) + ) + (component) +) diff --git a/test/wasm-tools/export-ascription.wast b/test/wasm-tools/export-ascription.wast new file mode 100644 index 00000000..ca70736e --- /dev/null +++ b/test/wasm-tools/export-ascription.wast @@ -0,0 +1,44 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "f" (func $f)) + (export "f2" (func $f) (func)) + ) +) + +;; subtyping works +(component + (component + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) +) + +;; make sure subtyping works in the right direction +(assert_invalid + (component + (import "f" (instance $i)) + (export "f2" (instance $i) (instance (export "f" (func)))) + ) + "ascribed type of export is not compatible") + +;; make sure the type is actually changed +(assert_invalid + (component + (import "f" (func $f)) + + (component $c + (import "f" (instance $i (export "f" (func)))) + (export "f2" (instance $i) (instance)) + ) + + (instance $c (instantiate $c (with "f" (instance (export "f" (func $f)))))) + + (component $consume + (import "arg" (instance $i (export "f" (func)))) + ) + + (instance (instantiate $consume (with "arg" (instance $c "f2")))) + ) + "missing expected export `f`") diff --git a/test/wasm-tools/export-introduces-alias.wast b/test/wasm-tools/export-introduces-alias.wast new file mode 100644 index 00000000..40d33efa --- /dev/null +++ b/test/wasm-tools/export-introduces-alias.wast @@ -0,0 +1,48 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "x" (func $f)) + + (export $g "g" (func $f)) + (export $g2 "g2" (func $g)) + ) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i (export "t" (type (eq $t))))) + (alias export $i "t" (type $my-t)) + )) +) + +(component + (type (component + (type $t u8) + (import "x" (instance $i + (export "i" (instance + (export "t" (type (eq $t))) + )) + )) + (alias export $i "i" (instance $my-i)) + (alias export $my-i "t" (type $my-t)) + )) +) + +(assert_malformed + (component quote + "(type (instance" + "(type $t u8)" + "(export \"t\" (type $t (eq $t)))" + "))" + ) + "duplicate type identifier") + +(component + (type (instance + (type $t u8) + (export "t" (type $t2 (eq $t))) + (export "t2" (type $t3 (eq $t2))) + )) +) diff --git a/test/wasm-tools/export.wast b/test/wasm-tools/export.wast new file mode 100644 index 00000000..73d094c8 --- /dev/null +++ b/test/wasm-tools/export.wast @@ -0,0 +1,63 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component (export "" (instance 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (component 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (core module 0))) + "index out of bounds") + +(assert_invalid + (component (export "" (func 0))) + "index out of bounds") + +(component + (component + (import "a" (instance $i)) + (import "b" (core module $m)) + (import "c" (component $c)) + (import "e" (func $f)) + + (export "f" (instance $i)) + (export "g" (core module $m)) + (export "h" (component $c)) + (export "j" (func $f)) + ) +) + +(component + (component + (import "a" (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; import/exports can overlap on ids +(component + (component + (import (interface "wasi:http/types@2.0.0") (func)) + (export (interface "wasi:http/types@2.0.0") (func 0)) + ) +) + +;; cannot export some types of strings +(assert_invalid + (component (type (component (export "integrity=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "url=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "relative-url=" (func))))) + "not a valid extern name") +(assert_invalid + (component (type (component (export "locked-dep=" (func))))) + "not a valid export name") +(assert_invalid + (component (type (component (export "unlocked-dep=" (func))))) + "not a valid export name") diff --git a/test/wasm-tools/func.wast b/test/wasm-tools/func.wast new file mode 100644 index 00000000..4a207f99 --- /dev/null +++ b/test/wasm-tools/func.wast @@ -0,0 +1,146 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (func (param "foo" string))) + (import "b" (func (param "foo" string) (param "bar" s32) (param "baz" u32))) + (import "c" (func (result (tuple u8)))) +) + +(component definition + (import "a" (func)) + (import "b" (func (param "p1" string))) + (import "c" (func (result u32))) + (import "d" (func (param "p1" bool) (result string))) +) + + +(assert_invalid + (component + (type (func (param "foo" string) (param "FOO" u32))) + ) + "function parameter name `FOO` conflicts with previous parameter name `foo`" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "foo") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "tuple") (result (tuple s8 u8)) + (canon lift (core func $i "foo")) + ) + ) + "canonical option `memory` is required" +) + +(component definition + (import "a" (func $log (param "msg" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) +) + +(component + (core module $m + (memory (export "memory") 1) + (func (export "ret-list") (result i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "ret-list") (result (list u8)) + (canon lift (core func $i "ret-list") (memory $i "memory")) + ) +) + +(component + (type $big (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (component $c + (import "big" (func $big (type $big))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $big (canon lower (func $big) (memory $libc "memory"))) + ) +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param i32)) + ) + (core instance $m (instantiate $m)) + + (type $roundtrip (func + (param "p1" u32) (param "p2" u32) (param "p3" u32) (param "p4" u32) (param "p5" u32) + (param "p6" u32) (param "p7" u32) (param "p8" u32) (param "p9" u32) (param "p10" u32) + (param "p11" u32) (param "p12" u32) (param "p13" u32) (param "p14" u32) (param "p15" u32) + (param "p16" u32) (param "p17" u32) (param "p18" u32) (param "p19" u32) (param "p20" u32) + )) + + (func $roundtrip (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory")) + ) + (export "roundtrip" (func $roundtrip)) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (import "a" (func $log (result string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func (canon lower (func $log) (memory $libc "memory"))) + ) + "canonical option `realloc` is required" +) + +(assert_invalid + (component + (core module $m + (memory (export "memory") 1) + (func (export "param-list") (param i32 i32) unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "param-list") (param "bytes" (list u8)) + (canon lift (core func $i "param-list") (memory $i "memory")) + ) + ) + "canonical option `realloc` is required" +) + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\01\01" ;; invalid result encoding + ) + "invalid leading byte (0x1) for number of results") + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\07\05" ;; component type section, 5 bytes + "\01" ;; 1 count + "\40" ;; component function type + "\00" ;; 0 parameters + "\02\00" ;; invalid result encoding + ) + "invalid leading byte (0x2) for component function results") diff --git a/test/wasm-tools/import.wast b/test/wasm-tools/import.wast new file mode 100644 index 00000000..b226157e --- /dev/null +++ b/test/wasm-tools/import.wast @@ -0,0 +1,359 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (component + (import "a" (func)) + (import "b" (instance)) + (import "c" (instance + (export "a" (func)) + )) + (import "d" (component + (import "a" (core module)) + (export "b" (func)) + )) + (type $t (func)) + (import "e" (type (eq $t))) + ) +) + +(assert_invalid + (component + (type $f (func)) + (import "a" (instance (type $f))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $f (func)) + (import "a" (core module (type $f))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $f string) + (import "a" (func (type $f))) + ) + "type index 0 is not a function type") + +;; Disallow duplicate imports for core wasm modules +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core module + (import "" "" (func)) + (import "" "" (func)) + ) + ) + "duplicate import name `:`") +(assert_invalid + (component + (core type (module + (import "" "a" (func)) + (import "" "a" (func)) + )) + ) + "duplicate import name `:a`") +(assert_invalid + (component + (core module + (import "" "a" (func)) + (import "" "a" (func)) + ) + ) + "duplicate import name `:a`") + +(assert_invalid + (component + (import "a" (func)) + (import "a" (func)) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "a" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (func (type 100))) + ) + "type index out of bounds") + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (func (type 100) (canon lift (core func $i ""))) + ) + "type index out of bounds") + +(component definition + (import "wasi:http/types" (func)) + (import "wasi:http/types@1.0.0" (func)) + (import "wasi:http/types@2.0.0" (func)) + (import "a-b:c-d/e-f@123456.7890.488" (func)) + (import "a:b/c@1.2.3" (func)) + (import "a:b/c@0.0.0" (func)) + (import "a:b/c@0.0.0+abcd" (func)) + (import "a:b/c@0.0.0+abcd-efg" (func)) + (import "a:b/c@0.0.0-abcd+efg" (func)) + (import "a:b/c@0.0.0-abcd.1.2+efg.4.ee.5" (func)) +) + +(assert_invalid + (component + (import "wasi:http/types" (func)) + (import "wasi:http/types" (func)) + ) + "conflicts with previous name") + +(assert_invalid + (component (import "" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "wasi:/" (func))) + "not in kebab case") +(assert_invalid + (component (import ":/" (func))) + "not in kebab case") +(assert_invalid + (component (import "wasi/http" (func))) + "`wasi/http` is not in kebab case") +(assert_invalid + (component (import "wasi:http/TyPeS" (func))) + "`TyPeS` is not in kebab case") +(assert_invalid + (component (import "WaSi:http/types" (func))) + "`WaSi` is not in kebab case") +(assert_invalid + (component (import "wasi:HtTp/types" (func))) + "`HtTp` is not in kebab case") +(assert_invalid + (component (import "wasi:http/types@" (func))) + "empty string") +(assert_invalid + (component (import "wasi:http/types@." (func))) + "unexpected character '.'") +(assert_invalid + (component (import "wasi:http/types@1." (func))) + "unexpected end of input") +(assert_invalid + (component (import "wasi:http/types@a.2" (func))) + "unexpected character 'a'") +(assert_invalid + (component (import "wasi:http/types@2.b" (func))) + "unexpected character 'b'") +(assert_invalid + (component (import "wasi:http/types@2.0x0" (func))) + "unexpected character 'x'") +(assert_invalid + (component (import "wasi:http/types@2.0.0+" (func))) + "empty identifier segment") +(assert_invalid + (component (import "wasi:http/types@2.0.0-" (func))) + "empty identifier segment") +(assert_invalid + (component (import "foo:bar:baz/qux" (func))) + "expected `/` after package name") +(assert_invalid + (component (import "foo:bar/baz/qux" (func))) + "trailing characters found: `/qux`") + +(component + (component + (import "a" (func $a)) + (export "a" (func $a)) + ) +) + +(component definition + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc}>" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep=" (func)) + (import "unlocked-dep==1.2.3 <1.2.3}>" (func)) + (import "unlocked-dep==1.2.3-rc <1.2.3}>" (func)) +) + +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "unlocked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `{` at `>`") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "expected `>=` or `<` at start of version range") +(assert_invalid + (component (import "unlocked-dep=" (func))) + "`xyz` is not a valid semver") +(assert_invalid + (component (import "unlocked-dep==2.3.4}>" (func))) + "`1.2.3 >=2.3.4` is not a valid semver") + +(component definition + (import "locked-dep=" (func)) + (import "locked-dep=" (func)) + (import "locked-dep=,integrity=" (func)) + (import "locked-dep=,integrity=" (func)) +) + +(assert_invalid + (component (import "locked-dep=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "locked-dep=<" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=<:a>" (func))) + "`` is not in kebab case") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=" (func))) + "is not a valid semver") +(assert_invalid + (component (import "locked-dep=` at ``") +(assert_invalid + (component (import "locked-dep=," (func))) + "expected `integrity=<`") +(assert_invalid + (component (import "locked-dep=x" (func))) + "trailing characters found: `x`") + +(component definition + (import "url=<>" (func)) + (import "url=" (func)) + (import "url=,integrity=" (func)) +) + +(assert_invalid + (component (import "url=" (func))) + "expected `<` at ``") +(assert_invalid + (component (import "url=<" (func))) + "failed to find `>`") +(assert_invalid + (component (import "url=<<>" (func))) + "url cannot contain `<`") + +(assert_invalid + (component + (import "relative-url=<>" (func)) + (import "relative-url=" (func)) + (import "relative-url=,integrity=" (func)) + ) + "not a valid extern name") + +(assert_invalid + (component (import "relative-url=" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<" (func))) + "not a valid extern name") +(assert_invalid + (component (import "relative-url=<<>" (func))) + "not a valid extern name") + +(component definition + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=< sha512-a sha256-b >" (func)) + (import "integrity=< sha512-a?abcd >" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) + (import "integrity=" (func)) +) +(assert_invalid + (component (import "integrity=<>" (func))) + "integrity hash cannot be empty") +(assert_invalid + (component (import "integrity=" (func))) + "expected `-` after hash algorithm") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "not valid base64") +(assert_invalid + (component (import "integrity=" (func))) + "unrecognized hash algorithm") + +;; Prior to WebAssembly/component-model#263 this was a valid component. +;; Specifically the 0x01 prefix byte on the import was valid. Nowadays that's +;; not valid in the spec but it's accepted for backwards compatibility. This +;; tests is here to ensure such compatibility. In the future this test should +;; be changed to `(assert_invalid ...)` +(component definition binary + "\00asm" "\0d\00\01\00" ;; component header + + "\07\05" ;; type section, 5 bytes large + "\01" ;; 1 count + "\40" ;; function + "\00" ;; parameters, 0 count + "\01\00" ;; results, named, 0 count + + "\0a\06" ;; import section, 6 bytes large + "\01" ;; 1 count + "\01" ;; prefix byte of 0x01 (invalid by the spec nowadays) + "\01a" ;; name = "a" + "\01\00" ;; type = func ($type 0) +) diff --git a/test/wasm-tools/imports-exports.wast b/test/wasm-tools/imports-exports.wast new file mode 100644 index 00000000..e650c8c8 --- /dev/null +++ b/test/wasm-tools/imports-exports.wast @@ -0,0 +1,26 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; With what's defined so far, we can define a component that imports, links and exports other components: + +(component + (component + (import "c" (instance $c + (export "f" (func (result string))) + )) + (import "d" (component $D + (import "c" (instance $c + (export "f" (func (result string))) + )) + (export "g" (func (result string))) + )) + (instance $d1 (instantiate $D + (with "c" (instance $c)) + )) + (instance $d2 (instantiate $D + (with "c" (instance + (export "f" (func $d1 "g")) + )) + )) + (export "d2" (instance $d2)) + ) +) diff --git a/test/wasm-tools/inline-exports.wast b/test/wasm-tools/inline-exports.wast new file mode 100644 index 00000000..2c3ff567 --- /dev/null +++ b/test/wasm-tools/inline-exports.wast @@ -0,0 +1,9 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type (export "foo") u8) +) + +(assert_malformed + (component quote "(type (component (type (export \"\") (func))))") + "unexpected token") diff --git a/test/wasm-tools/instance-type.wast b/test/wasm-tools/instance-type.wast new file mode 100644 index 00000000..2f4b1404 --- /dev/null +++ b/test/wasm-tools/instance-type.wast @@ -0,0 +1,234 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; instances +(component + (type (instance)) + + (type $foo (func)) + + (type $t (func (result string))) + + (core type (module + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "b" (func $foo)) + (export "c" (func)) + (export "d" (func $foo)) + (export "e" (func (type $local_type))) + (export "f" (func (param i32))) + (export "g" (func (param i32) (result i32 i64))) + (export "h" (func (type $local_type) (result i32))) + + ;; globals + (export "i" (global i32)) + (export "j" (global $foo i32)) + (export "k" (global (mut i32))) + + ;; tables + (export "l" (table 1 funcref)) + (export "m" (table $foo 1 funcref)) + + ;; memory + (export "n" (memory 1)) + (export "o" (memory $foo 1)) + (export "p" (memory 1 2)) + (export "q" (memory 1 2 shared)) + )) + + (type $outer (instance + (type $local_type (func)) + ;; functions + (export "a" (func)) + (export "a2" (func (type $local_type))) + (export "b" (func)) + (export "c" (func)) + (export "d" (func)) + (export "e" (func (type $t))) + (export "f" (func (param "f" string))) + (export "g" (func (param "g" s32) (result u32))) + (export "h" (func (type $t))) + + ;; components + (type $component_type (component)) + (export "c1" (component)) + (export "c2" (component (import "i1" (func)))) + (export "c3" (component (export "e1" (func)))) + (export "c4" (component (type $component_type))) + (export "c5" (component + (type $nested_func_type (func)) + (alias outer $outer $local_type (type $my_type)) + (import "i1" (func (type $nested_func_type))) + (import "i2" (component)) + (export "e1" (func (type $my_type))) + (export "e2" (component)) + )) + )) +) + +;; expand inline types +(component + (type (instance (export "a" (instance)))) +) + +;; reference outer types +(component + (type (instance + (type $t (instance)) + (export "a" (instance (type $t))) + )) + (type $x (instance)) + (type (instance (export "a" (instance (type $x))))) +) + +;; recursive +(component + (type (instance (export "a" (core module + (type $functype (func)) + + (export "a" (func)) + (export "b" (func (type 0))) + (export "c" (func (param i32))) + (export "d" (func (type $functype))) + + ;; globals + (export "e" (global i32)) + (export "f" (global (mut i32))) + + ;; tables + (export "g" (table 1 funcref)) + + ;; memory + (export "h" (memory 1)) + (export "i" (memory 1 2)) + (export "j" (memory 1 2 shared)) + )))) +) + +;; modules +(component + (core type (module)) + + (core type $foo (module)) + + (type $empty (func)) + (type $i (instance)) + + (core type (module + (type $empty (func)) + (import "" "a" (func)) + (import "" "b" (func (type $empty))) + (import "" "c" (func (param i32))) + (import "" "d" (func (param i32) (result i32))) + + (import "" "e" (global i32)) + (import "" "f" (memory 1)) + (import "" "g" (table 1 funcref)) + + (export "a" (func)) + (export "b" (global i32)) + (export "c" (memory 1)) + (export "d" (table 1 funcref)) + + (export "e" (func (type $empty))) + (export "f" (func (param i32))) + )) + + (type (component + (import "a" (func)) + (import "b" (func (type $empty))) + (import "c" (func (param "c" s32))) + (import "d" (func (param "d" s32) (result s32))) + + (import "h" (instance)) + (import "i" (instance (type $i))) + (import "j" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (import "k" (core module)) + (import "l" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + + (export "m" (func)) + (export "n" (func (type $empty))) + (export "o" (func (param "f" s32))) + + (export "p" (instance + (export "a" (func)) + (export "b" (func (type $empty))) + (export "c" (func (param "c" s32))) + )) + + (export "q" (core module + (type $empty (func)) + (import "" "a" (func (type $empty))) + (import "" "b" (func (param i32))) + (export "a" (func (type $empty))) + (export "b" (func (param i32))) + )) + )) +) + +(assert_invalid + (component + (type (instance + (export "a" (func)) + (export "a" (func))))) + "export name `a` conflicts with previous name `a`") + +(assert_invalid + (component + (type $t (func)) + (type (instance + (export "a" (instance (type $t))) + ))) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (instance + (export "a" (core module (type $t))) + ))) + "core type index 0 is not a module type") + +(assert_malformed + (component quote + "(type $t (func))" + "(type (instance (export \"a\" (core module (type $t)))))" + ) + "unknown core type") + +(assert_invalid + (component + (type $t (record (field "a" string))) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (func (type $t))) + ))) + "type index 0 is not a function type") + +(assert_invalid + (component + (type $t (instance)) + (type (instance + (export "a" (instance + (export "a" (func (type $t))) + )) + ))) + "type index 0 is not a function type") diff --git a/test/wasm-tools/instantiate.wast b/test/wasm-tools/instantiate.wast new file mode 100644 index 00000000..cb992394 --- /dev/null +++ b/test/wasm-tools/instantiate.wast @@ -0,0 +1,976 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "a" (core module $m)) + (core instance $a (instantiate $m)) +) + +(component + (component + (import "a" (func $i)) + (import "b" (component $c (import "a" (func)))) + (instance (instantiate $c (with "a" (func $i)))) + ) +) + +(component + (component + (import "a" (component $i)) + (import "b" (component $c (import "a" (component)))) + (instance (instantiate $c (with "a" (component $i)))) + ) +) + +(component + (component + (import "a" (core module $i)) + (import "b" (component $c (import "a" (core module)))) + (instance (instantiate $c (with "a" (core module $i)))) + ) +) + +(component + (component + (import "a" (instance $i)) + (import "b" (component $c (import "a" (instance)))) + (instance (instantiate $c (with "a" (instance $i)))) + ) +) + +(component definition + (import "a" (core module $m + (import "" "a" (func)) + (import "" "b" (global i32)) + (import "" "c" (table 1 funcref)) + (import "" "d" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $x)))) +) + +(component definition + (import "a" (core module $m + (import "" "d" (func)) + (import "" "c" (global i32)) + (import "" "b" (table 1 funcref)) + (import "" "a" (memory 1)) + )) + (import "b" (core module $m2 + (export "a" (func)) + (export "b" (global i32)) + (export "c" (table 1 funcref)) + (export "d" (memory 1)) + )) + (core instance $x (instantiate $m2)) + + (core instance (instantiate $m (with "" (instance + (export "d" (func $x "a")) + (export "c" (global $x "b")) + (export "b" (table $x "c")) + (export "a" (memory $x "d")) + )))) +) + +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (core module)) + )) + )) + (import "b" (component $m2 + (export "b" (core module)) + )) + (instance $x (instantiate $m2)) + + (instance (instantiate $m (with "a" (instance + (export "a" (core module $x "b")) + )))) + ) +) + +(component + (component + (import "a" (component $c + (import "a" (core module)) + (import "b" (func)) + (import "c" (component)) + (import "d" (instance)) + )) + (core module $m (import "b")) + (func $f (import "c")) + (component $c2 (import "d")) + (instance $i (import "e")) + + (instance + (instantiate $c + (with "a" (core module $m)) + (with "b" (func $f)) + (with "c" (component $c2)) + (with "d" (instance $i)) + ) + ) + + (core instance $c (instantiate $m)) + (core instance (instantiate $m)) + + ;; inline exports/imports + (type $empty (instance)) + (instance $d (import "g") (type $empty)) + (instance (import "h")) + (instance (import "i") + (export "x" (func))) + (instance (export "j") (export "k") (import "x")) + ) +) + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") +(assert_invalid + (component + (instance (instantiate 0)) + ) + "unknown component") +(assert_invalid + (component + (import "a" (core module)) + (core instance (instantiate 1)) + ) + "unknown module") + +(component + (component + (import "a" (func $f)) + (import "b" (component $c)) + (instance (instantiate $c (with "a" (func $f)))) + ) +) +(assert_invalid + (component + (import "a" (core module $m (import "" "" (func)))) + (core instance (instantiate $m)) + ) + "missing module instantiation argument") +(assert_invalid + (component + (import "a" (component $m (import "a" (func)))) + (instance (instantiate $m)) + ) + "missing import named `a`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (component $c)) + (instance $i (instantiate $m (with "a" (component $c)))) + ) + "expected func, found component") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func $f (result string))) + (instance $i (instantiate $m (with "a" (func $f)))) + ) + "expected a result, found none") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (func)) + )) + (import "b" (func (param "i" string))) + (instance $i (instantiate $m (with "a" (func 0)))) + ) + "expected 0 parameters, found 1") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "type mismatch in import `::`") + +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module)) + )) + (import "b" (core module $i + (import "" "foobar" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected import `::foobar`") +(assert_invalid + (component + (import "a" (component $m + (import "a" (core module (export "x" (func)))) + )) + (import "b" (core module $i)) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) + "missing expected export `x`") + +;; it's ok to give a module with fewer imports +(component + (component + (import "a" (component $m + (import "a" (core module + (import "" "" (global i32)) + (import "" "f" (func)) + )) + )) + (import "b" (core module $i + (import "" "" (global i32)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) + +;; export subsets +(component + (component + (import "a" (component $m + (import "a" (core module + (export "" (func)) + )) + )) + (import "b" (core module $i + (export "" (func)) + (export "a" (func)) + )) + (instance $i (instantiate $m (with "a" (core module $i)))) + ) +) +(component + (component + (import "a" (component $m + (import "a" (instance + (export "a" (func)) + )) + )) + (import "b" (instance $i + (export "a" (func)) + (export "b" (func)) + )) + (instance (instantiate $m (with "a" (instance $i)))) + ) +) + + +;; ============================================================================ +;; core wasm type checking + +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (param i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (result i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected: (func)") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (global i32)))) + (import "m2" (core module $m2 (export "" (global i64)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected global type i32, found i64") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 externref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "expected table element type funcref, found externref") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 1 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in table limits") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) + (import "m2" (core module $m2 (export "" (memory 1)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in the shared flag for memories") +(assert_invalid + (component + (import "m1" (core module $m1 (import "" "" (memory 1)))) + (import "m2" (core module $m2 (export "" (memory 0)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) + ) + "mismatch in memory limits") +(assert_invalid + (component + (import "m1" (core module $m1 (export "g" (func)))) + (component $c + (import "m" (core module (export "g" (global i32)))) + ) + (instance (instantiate $c (with "m" (core module $m1)))) + ) + "type mismatch in export `g`") + +(assert_invalid + (component + (core instance (instantiate 0)) + ) + "unknown module") + +(component + (component $m + (core module $sub (export "module") + (func $f (export "") (result i32) + i32.const 5)) + ) + (instance $a (instantiate $m)) + (alias export $a "module" (core module $sub)) + (core instance $b (instantiate $sub)) + + (core module $final + (import "" "" (func $b (result i32))) + (func (export "get") (result i32) + call $b)) + + (core instance (instantiate $final (with "" (instance $b)))) +) + +(assert_invalid + (component (instance $i (export "" (func 0)))) + "function index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (component 0)))) + "index out of bounds") + +(assert_invalid + (component (instance (export "" (instance 0)))) + "index out of bounds") + +(assert_invalid + (component (instance $i (export "" (core module 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (func 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (table 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (global 0)))) + "index out of bounds") + +(assert_invalid + (component (core instance (export "" (memory 0)))) + "index out of bounds") + +(assert_invalid + (component + (core module $m) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``" +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance (instantiate $m + (with "" (instance $i)) + (with "" (instance $i)) + )) + ) + "duplicate module instantiation argument named ``") + +(assert_invalid + (component + (core module $m1 (func (export ""))) + (core module $m2 (import "" "" (global i32))) + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) + ) + "expected global, found func") + +(assert_invalid + (component + (component $m) + (instance $i (instantiate $m)) + (instance (instantiate $m + (with "a" (instance $i)) + (with "a" (instance $i)) + )) + ) + "instantiation argument `a` conflicts with previous argument `a`") + +(assert_invalid + (component + (component $c (import "a" (func))) + (instance (instantiate $c + (with "a" (component $c)) + )) + ) + "expected func, found component") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (core module 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (instance 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (func 0)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance (instantiate $c + (with "" (component 100)) + )) + ) + "index out of bounds") + +(assert_invalid + (component + (component $c) + (instance + (export "a" (component $c)) + (export "a" (component $c)) + ) + ) + "export name `a` conflicts with previous name `a`") + +(component + (component + (import "a" (instance $i)) + (import "b" (func $f)) + (import "c" (component $c)) + (import "d" (core module $m)) + (instance + (export "a" (instance $i)) + (export "b" (func $f)) + (export "c" (component $c)) + (export "d" (core module $m)) + ) + ) +) + +(component + (core module $m + (func (export "1")) + (memory (export "2") 1) + (table (export "3") 1 funcref) + (global (export "4") i32 i32.const 0) + ) + (core instance $i (instantiate $m)) + (core instance + (export "a" (func $i "1")) + (export "b" (memory $i "2")) + (export "c" (table $i "3")) + (export "d" (global $i "4")) + ) +) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (func $i "")) + (export "" (func $i "")) + ) + ) + "export name `` already defined") + +(assert_invalid + (component + (component $c) + (instance $i (instantiate $c)) + (export "a" (instance $i "a")) + ) + "no export named `a`") + +(assert_invalid + (component + (export "a" (instance 100 "a")) + ) + "index out of bounds") + +(assert_invalid + (component + (import "a" (core module $libc + (export "memory" (memory 1)) + (export "table" (table 0 funcref)) + (export "func" (func)) + (export "global" (global i32)) + (export "global mut" (global (mut i64))) + )) + (core instance $libc (instantiate $libc)) + (alias core export $libc "memory" (core memory $mem)) + (alias core export $libc "table" (core table $tbl)) + (alias core export $libc "func" (core func $func)) + (alias core export $libc "global" (core global $global)) + (alias core export $libc "global mut" (core global $global_mut)) + + (import "x" (core module $needs_libc + (import "" "memory" (memory 1)) + (import "" "table" (table 0 funcref)) + (import "" "func" (func)) + (import "" "global" (global i32)) + (import "" "global mut" (global (mut i64))) + )) + + (core instance + (instantiate $needs_libc + (with "" (instance (export "memory" (memory $mem)))) + ) + ) + ) + "module instantiation argument `` does not export an item named `table`") + +;; Ensure a type can be an instantiation argument +(component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + (component + (type (tuple u32 u32)) + (import "a" (type (eq 0))) + ) + (instance (instantiate 0 + (with "a" (type 1)) + ) + ) +) + +(assert_invalid + (component + (type $t (tuple string string)) + (import "a" (type $a (eq $t))) + (component $c + (type $t (tuple u32 u32)) + (import "a" (type (eq $t))) + ) + (instance (instantiate $c + (with "a" (type $a)) + ) + ) + ) + "expected primitive `u32` found primitive `string`") + + +;; subtyping for module imports reverses order of imports/exports for the +;; subtyping check +;; +;; Here `C` imports a module, and the module itself imports a table of min size +;; 1. A module import which imports a min-size table of 0, however, is valid to +;; supply for this since it'll already be given at least 1 anyway. +;; +;; Similarly for exports `C` imports a module that exports a table of at least +;; size 1. If it's given a module that exports a larger table that's ok too. +(component + (core module $a + (import "" "" (table 0 funcref)) + (table (export "x") 2 funcref) + ) + (component $C + (import "a" (core module + (import "" "" (table 1 funcref)) + (export "x" (table 1 funcref)) + )) + ) + (instance (instantiate $C (with "a" (core module $a)))) +) + +;; same as above but for memories +(component + (core module $a1 (import "" "" (memory 0))) + (core module $a2 (memory (export "x") 2)) + (component $C + (import "a1" (core module (import "" "" (memory 1)))) + (import "a2" (core module (export "x" (memory 1)))) + ) + (instance (instantiate $C + (with "a1" (core module $a1)) + (with "a2" (core module $a2)) + )) +) + +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "y" u32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "expected parameter named `y`, found `x`") +(assert_invalid + (component + (import "x" (func $x (param "x" u32))) + (import "y" (component $c + (import "x" (func (param "x" s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch in function parameter `x`") +(assert_invalid + (component + (import "x" (func $x (result u32))) + (import "y" (component $c + (import "x" (func (result s32))) + )) + + (instance (instantiate $c (with "x" (func $x)))) + ) + "type mismatch with result type") + +(assert_invalid + (component + (import "x" (instance $x (export "a" (func)))) + (import "y" (component $c + (import "x" (instance $x (export "a" (component)))) + )) + + (instance (instantiate $c (with "x" (instance $x)))) + ) + "type mismatch in instance export `a`") + +(assert_invalid + (component + (import "y" (component $c + (type $t u32) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "f" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected primitive, found record") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "f" u32))) + (import "x" (type (eq $t))) + )) + + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected record, found u32") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $f (tuple u8)) + (type $x (record (field "x" $f))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected u32, found tuple") + +(assert_invalid + (component + (import "y" (component $c + (type $f (option s32)) + (type $t (record (field "x" $f))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in record field `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "y" u32) (field "z" u64))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 fields, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (record (field "a" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (record (field "b" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected field name `a`, found `b`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32) (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 cases, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "y" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case named `x`, found `y`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x"))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have a type, found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x"))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected case `x` to have no type") + +(assert_invalid + (component + (import "y" (component $c + (type $t (variant (case "x" u32))) + (import "x" (type (eq $t))) + )) + + (type $x (variant (case "x" s32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in variant case `x`") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u32 u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected 1 types, found 2") + +(assert_invalid + (component + (import "y" (component $c + (type $t (tuple u8)) + (import "x" (type (eq $t))) + )) + + (type $x (tuple u16)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in tuple field 0") + +(assert_invalid + (component + (import "y" (component $c + (type $t (flags "a")) + (import "x" (type (eq $t))) + )) + + (type $x (flags "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in flags elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (enum "a")) + (import "x" (type (eq $t))) + )) + + (type $x (enum "x")) + (instance (instantiate $c (with "x" (type $x)))) + ) + "mismatch in enum elements") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result s32)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in ok variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error s32))) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "type mismatch in err variant") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result u32)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result u32)) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected ok type, but found none") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result)) + (import "x" (type (eq $t))) + )) + + (type $x (result (error u32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type to not be present") + +(assert_invalid + (component + (import "y" (component $c + (type $t (result (error u32))) + (import "x" (type (eq $t))) + )) + + (type $x (result)) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected err type, but found none") diff --git a/test/wasm-tools/invalid.wast b/test/wasm-tools/invalid.wast new file mode 100644 index 00000000..267b31f8 --- /dev/null +++ b/test/wasm-tools/invalid.wast @@ -0,0 +1,34 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core type (module + (import "" "" (func (type 1))) + )) + (type (func)) + ) + "type index out of bounds") + +(assert_malformed + (component quote + "(export \"\" (func $foo))" + ) + "unknown func") + +(assert_malformed + (component quote + "(alias outer 100 $foo (type $foo))" + ) + "outer count of `100` is too large") + +(assert_malformed + (component quote + "(alias outer $nonexistent $foo (type $foo))" + ) + "outer component `nonexistent` not found") + +(assert_malformed + (component quote + "(import \"x\" (func $x))" + "(component (export \"x\" (func $x)))") + "outer item `x` is not a module, type, or component") diff --git a/test/wasm-tools/link.wast b/test/wasm-tools/link.wast new file mode 100644 index 00000000..72023652 --- /dev/null +++ b/test/wasm-tools/link.wast @@ -0,0 +1,14 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Based on this, we can link two modules $A and $B together with the following component: + +(component + (core module $A + (func (export "one") (result i32) (i32.const 1)) + ) + (core module $B + (func (import "a" "one") (result i32)) + ) + (core instance $a (instantiate $A)) + (core instance $b (instantiate $B (with "a" (instance $a)))) +) diff --git a/test/wasm-tools/lots-of-aliases.wast b/test/wasm-tools/lots-of-aliases.wast new file mode 100644 index 00000000..32e1a27a --- /dev/null +++ b/test/wasm-tools/lots-of-aliases.wast @@ -0,0 +1,179 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $m + (memory (export "m") 1) + (table (export "t") 1 funcref) + (global (export "g") i32 i32.const 0) + (func (export "f")) + ) + (core instance $i (instantiate $m)) + + ;; 160 memories (4 per row 40 rows) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) (alias core export $i "m" (core memory)) + + ;; 160 tables (4 per row 40 rows) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) (alias core export $i "t" (core table)) + + ;; 160 globals (4 per row 40 rows) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) (alias core export $i "g" (core global)) + + ;; 160 functions (4 per row 40 rows) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) + (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) (alias core export $i "f" (core func)) +) diff --git a/test/wasm-tools/lower.wast b/test/wasm-tools/lower.wast new file mode 100644 index 00000000..5b9e13bf --- /dev/null +++ b/test/wasm-tools/lower.wast @@ -0,0 +1,17 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (import "f" (func $f (param "x" (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") + +(assert_invalid + (component + (import "f" (func $f (result (list u8)))) + (core func $f (canon lower (func $f) + )) + ) + "canonical option `memory` is required") diff --git a/test/wasm-tools/memory64.wast b/test/wasm-tools/memory64.wast new file mode 100644 index 00000000..0ec55341 --- /dev/null +++ b/test/wasm-tools/memory64.wast @@ -0,0 +1,54 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $A + (import "" "" (memory 1))) + (core module $B + (memory (export "") i64 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(assert_invalid + (component + (core module $A + (import "" "" (memory i64 1))) + (core module $B + (memory (export "") 1)) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) + ) + "mismatch in index type used for memories") + +(component + (core module $A + (memory (export "m") i64 1)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + + (core module $B (import "" "" (memory i64 1))) + (core instance (instantiate $B (with "" (instance (export "" (memory $m)))))) +) + +(component + (core module $A + (table (export "m") i64 1 funcref)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core table $m)) + + (core module $B (import "" "" (table i64 1 funcref))) + (core instance (instantiate $B (with "" (instance (export "" (table $m)))))) +) + +(assert_invalid + (component + (import "x" (func $x (param "x" string))) + (core module $A + (memory (export "m") i64 1)) + (core instance $A (instantiate $A)) + (alias core export $A "m" (core memory $m)) + (core func (canon lower (func $x) (memory $m))) + ) + "canonical ABI memory is not a 32-bit linear memory") diff --git a/test/wasm-tools/module-link.wast b/test/wasm-tools/module-link.wast new file mode 100644 index 00000000..119da23b --- /dev/null +++ b/test/wasm-tools/module-link.wast @@ -0,0 +1,98 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $Wasi (instance)) + (component $B) + (component $B_wrap + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B)) + ) +) + +(component + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + + (component $A + (type $Wasi (instance)) + (import "wasi" (instance (type $Wasi))) + + (core module $m + (func (export "a")) + ) + + (core instance $i (instantiate $m)) + (func (export "a") + (canon lift (core func $i "a")) + ) + ) + + (component $B + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "a1-x" (component $A + (import "wasi" (instance (type $Wasi))) + (export "a" (func)) + )) + (instance $a (instantiate $A (with "wasi" (instance $wasi)))) + + (core func $lower (canon lower (func $a "a"))) + (core module $b + (import "a" "a" (func)) + (func (export "b")) + ) + (core instance $b (instantiate $b + (with "a" (instance (export "a" (func $lower)))) + )) + (func (export "b") + (canon lift (core func $b "b")) + ) + ) + (component $B_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $b (instantiate $B + (with "wasi" (instance $wasi)) + (with "a1-x" (component $A))) + ) + (export "b" (func $b "b")) + ) + + (component $C + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "b1-x" (component $B + (import "wasi" (instance $wasi (type $Wasi))) + (export "b" (func)) + )) + (instance $b (instantiate $B (with "wasi" (instance $wasi)))) + (export "c" (func $b "b")) + ) + (component $C_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $c (instantiate $C + (with "wasi" (instance $wasi)) + (with "b1-x" (component $B_wrap)) + )) + (export "c" (func $c "c")) + ) + + (component $D + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "c1-x" (component $C + (import "wasi" (instance $wasi (type $Wasi))) + (export "c" (func)) + )) + (instance $c (instantiate $C (with "wasi" (instance $wasi)))) + (export "d" (func $c "c")) + ) + + (instance $d (instantiate $D + (with "wasi" (instance $wasi)) + (with "c1-x" (component $C_wrap)) + )) + + (export "d" (func $d "d")) +) diff --git a/test/wasm-tools/more-flags.wast b/test/wasm-tools/more-flags.wast new file mode 100644 index 00000000..ebcced0f --- /dev/null +++ b/test/wasm-tools/more-flags.wast @@ -0,0 +1,41 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") diff --git a/test/wasm-tools/naming.wast b/test/wasm-tools/naming.wast new file mode 100644 index 00000000..160df4d4 --- /dev/null +++ b/test/wasm-tools/naming.wast @@ -0,0 +1,130 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (func (import "a")) + (component) + (instance (instantiate 0 (with "NotKebab-Case" (func 0)))) +) + +(assert_invalid + (component + (import "f" (func)) + (instance (export "1" (func 0))) + ) + "`1` is not in kebab case" +) + +(assert_invalid + (component + (instance) + (alias export 0 "Xml" (func)) + ) + "instance 0 has no export named `Xml`" +) + +(assert_invalid + (component + (type (flags "a-1-c")) + ) + "flag name `a-1-c` is not in kebab case" +) + +(assert_invalid + (component + (type (enum "NevEr")) + ) + "enum tag name `NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (record (field "GoNnA" string))) + ) + "record field name `GoNnA` is not in kebab case" +) + +(assert_invalid + (component + (type (variant (case "GIVe" string))) + ) + "variant case name `GIVe` is not in kebab case" +) + + +(assert_invalid + (component + (type (func (param "yOu" string))) + ) + "function parameter name `yOu` is not in kebab case" +) + +(assert_invalid + (component + (type (component (export "NevEr" (func)))) + ) + "`NevEr` is not in kebab case" +) + +(assert_invalid + (component + (type (component (import "GonnA" (func)))) + ) + "`GonnA` is not in kebab case" +) + +(assert_invalid + (component + (type (instance (export "lET" (func)))) + ) + "`lET` is not in kebab case" +) + +(assert_invalid + (component + (instance (export "YoU")) + ) + "`YoU` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "DOWn")) + ) + "`DOWn` is not in kebab case" +) + +(assert_invalid + (component + (instance (import "A:b/c")) + ) + "character `A` is not lowercase in package name/namespace" +) +(assert_invalid + (component + (instance (import "a:B/c")) + ) + "character `B` is not lowercase in package name/namespace" +) +(component + (instance (import "a:b/c")) + (instance (import "a1:b1/c")) +) + +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a)))) +) + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[method]a.a" (func (param "self" (borrow $a)))) + ) + "import name `[method]a.a` conflicts with previous name `a`") + +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[static]a.a" (func)) + ) + "import name `[static]a.a` conflicts with previous name `a`") diff --git a/test/wasm-tools/nested-modules.wast b/test/wasm-tools/nested-modules.wast new file mode 100644 index 00000000..5e629ea5 --- /dev/null +++ b/test/wasm-tools/nested-modules.wast @@ -0,0 +1,50 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component definition + (import "i1" (core module)) + + (core module) + (core module) + + (core module (export "x")) + + (component + (core module) + ) + + (component + (core module $m) + (import "a" (func (param "p" string))) + (export "b" (core module $m)) + ) +) + +;; does the `import` use the type annotation specified later? +(component definition + (import "a" (core module)) + (core type (module)) +) + +;; be sure to typecheck nested modules +(assert_invalid + (component + (core module + (func + i32.add) + ) + ) + "type mismatch") + +;; interleave module definitions with imports/aliases and ensure that we +;; typecheck the module code section correctly +(component definition + (core module + (func (export "")) + ) + (import "a" (core module)) + (core module + (func (export "") (result i32) i32.const 5) + ) + (import "b" (instance (export "a" (core module)))) + (alias export 0 "a" (core module)) +) diff --git a/test/wasm-tools/resources.wast b/test/wasm-tools/resources.wast new file mode 100644 index 00000000..14509c54 --- /dev/null +++ b/test/wasm-tools/resources.wast @@ -0,0 +1,1195 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (type $x (resource (rep i32))) +) + +(component + (type $x (resource (rep i32))) + + (core func (canon resource.new $x)) + (core func (canon resource.rep $x)) + (core func (canon resource.drop $x)) +) + +(component definition + (import "x" (type $x (sub resource))) + + (core func (canon resource.drop $x)) +) + +(component + (core module $m + (func (export "dtor") (param i32)) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) +) + +(component + (type $x (resource (rep i32))) + (core func $f1 (canon resource.new $x)) + (core func $f2 (canon resource.rep $x)) + (core func $f3 (canon resource.drop $x)) + + (core module $m + (import "" "f1" (func (param i32) (result i32))) + (import "" "f2" (func (param i32) (result i32))) + (import "" "f3" (func (param i32))) + ) + + (core instance (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f2" (func $f2)) + (export "f3" (func $f3)) + )) + )) +) + +(assert_invalid + (component + (type $x (resource (rep i64))) + ) + "resources can only be represented by `i32`") + +(assert_invalid + (component + (type $x (own 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $x (borrow 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type $t u8) + (type $x (borrow $t)) + ) + "not a resource type") + +(assert_invalid + (component + (type $t u8) + (type $x (own $t)) + ) + "not a resource type") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.new $x)) + ) + "not a local resource") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (core func (canon resource.rep $x)) + ) + "not a local resource") + +(assert_invalid + (component + (type $t (tuple u32)) + (core func (canon resource.drop $t)) + ) + "not a resource type") + +(assert_invalid + (component + (core func (canon resource.drop 100)) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.drop 0)) + ) + "not a resource type") + +(assert_invalid + (component + (type (component)) + (core func (canon resource.new 0)) + ) + "not a resource type") + +(assert_invalid + (component + (core module $m + (func (export "dtor")) + ) + (core instance $m (instantiate $m)) + (type $x (resource (rep i32) (dtor (func $m "dtor")))) + (core func (canon resource.new $x)) + ) + "wrong signature for a destructor") + +(assert_invalid + (component + (type (resource (rep i32) (dtor (func 100)))) + ) + "function index out of bounds") + +(assert_invalid + (component + (import "x" (type $x (sub resource))) + (import "y" (type $y (sub resource))) + (import "z" (func $z (param "x" (own $x)) (param "y" (own $y)))) + + (component $c + (import "x" (type $x (sub resource))) + (import "z" (func (param "x" (own $x)) (param "y" (own $x)))) + ) + + (instance (instantiate $c (with "x" (type $x)) (with "z" (func $z)))) + ) + "resource types are not the same") + +(component + (type (component + (import "x" (type $x (sub resource))) + (export "y" (type (eq $x))) + (export "z" (type (sub resource))) + )) +) + +(assert_invalid + (component + (type (component + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(assert_invalid + (component + (type (instance + (type $x (resource (rep i32))) + )) + ) + "resources can only be defined within a concrete component") + +(component + (type (component + (import "x" (instance $i + (export "t" (type $t (sub resource))) + (export "f" (func (result (own $t)))) + )) + (alias export $i "t" (type $t)) + (export "f" (func (result (own $t)))) + )) +) + +(component definition + (import "fancy-fs" (instance $fancy-fs + (export "fs" (instance $fs + (export "file" (type (sub resource))) + )) + (alias export $fs "file" (type $file)) + (export "fancy-op" (func (param "f" (borrow $file)))) + )) +) + +(component $C + (type $T (list (tuple string bool))) + (type $U (option $T)) + (type $G (func (param "x" (list $T)) (result $U))) + (type $D (component + (alias outer $C $T (type $C_T)) + (type $L (list $C_T)) + (import "f" (func (param "x" $L) (result (list u8)))) + (import "g" (func (type $G))) + (export "g2" (func (type $G))) + (export "h" (func (result $U))) + (import "T" (type $T (sub resource))) + (import "i" (func (param "x" (list (own $T))))) + (export "T2" (type $T' (eq $T))) + (export "U" (type $U' (sub resource))) + (export "j" (func (param "x" (borrow $T')) (result (own $U')))) + )) +) + +(component definition + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) +) + +(component definition $C + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (import "T3" (type $T3 (eq $T2))) + (type $ListT1 (list (own $T1))) + (type $ListT2 (list (own $T2))) + (type $ListT3 (list (own $T3))) +) + +(component definition + (import "T" (type $T (sub resource))) + (import "U" (type $U (sub resource))) + (type $Own1 (own $T)) + (type $Own2 (own $T)) + (type $Own3 (own $U)) + (type $ListOwn1 (list $Own1)) + (type $ListOwn2 (list $Own2)) + (type $ListOwn3 (list $Own3)) + (type $Borrow1 (borrow $T)) + (type $Borrow2 (borrow $T)) + (type $Borrow3 (borrow $U)) + (type $ListBorrow1 (list $Borrow1)) + (type $ListBorrow2 (list $Borrow2)) + (type $ListBorrow3 (list $Borrow3)) +) + +(component + (component + (import "C" (component $C + (export "T1" (type (sub resource))) + (export "T2" (type $T2 (sub resource))) + (export "T3" (type (eq $T2))) + )) + (instance $c (instantiate $C)) + (alias export $c "T1" (type $T1)) + (alias export $c "T2" (type $T2)) + (alias export $c "T3" (type $T3)) + ) +) + +(component + (component $C + (type $r1 (export "r1") (resource (rep i32))) + (type $r2 (export "r2") (resource (rep i32))) + ) + (instance $c1 (instantiate $C)) + (instance $c2 (instantiate $C)) + (alias export $c1 "r1" (type $c1r1)) + (alias export $c1 "r2" (type $c1r2)) + (alias export $c2 "r1" (type $c2r1)) + (alias export $c2 "r2" (type $c2r2)) +) + +(component + (type $r (resource (rep i32))) + (export "r1" (type $r)) + (export "r2" (type $r)) +) + +(component + (type (component + (export "r1" (type (sub resource))) + (export "r2" (type (sub resource))) + )) +) + +(component + (type $r (resource (rep i32))) + (export $r1 "r1" (type $r)) + (export "r2" (type $r1)) +) + +(component + (type (component + (export "r1" (type $r1 (sub resource))) + (export "r2" (type (eq $r1))) + )) +) + +(component + (component $P + (import "C1" (component $C1 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (own $T)))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (import "foo" (func (param "t" (own $T)))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 (with "T" (type $R)))) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(component + (component + (import "C1" (component $C1 + (import "T1" (type $T1 (sub resource))) + (import "T2" (type $T2 (sub resource))) + (export "foo" (func (param "t" (tuple (own $T1) (own $T2))))) + )) + (import "C2" (component $C2 + (import "T" (type $T (sub resource))) + (export "foo" (func (param "t" (tuple (own $T) (own $T))))) + )) + (type $R (resource (rep i32))) + (instance $c1 (instantiate $C1 + (with "T1" (type $R)) + (with "T2" (type $R)) + )) + (instance $c2 (instantiate $C2 + (with "T" (type $R)) + (with "foo" (func $c1 "foo")) + )) + ) +) + +(assert_invalid + (component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.rep $R)) + ) + "not a local resource") + +(component + (component $C + (type $R (resource (rep i32))) + (export "R" (type $R)) + ) + (instance $c (instantiate $C)) + (alias export $c "R" (type $R)) + (core func (canon resource.drop $R)) +) + +(component + (component $C1 + (import "X" (type (sub resource))) + ) + (component $C2 + (import "C1" (component + (import "X" (type (sub resource))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (import "X" (type $X (sub resource))) + (import "f" (func $f (result (own $X)))) + (export "g" (func $f)) + ) + (component $C2 + (import "C1" (component + (import "X" (type $X (sub resource))) + (import "f" (func (result (own $X)))) + (export "g" (func (result (own $X)))) + )) + ) + (instance $c (instantiate $C2 (with "C1" (component $C1)))) +) + +(component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c1 "f")) + )) +) + +(assert_invalid + (component + (component $C1 + (type $X' (resource (rep i32))) + (export $X "X" (type $X')) + + (core func $f (canon resource.drop $X)) + (func (export "f") (param "X" (own $X)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + (instance $c2 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X")) + (with "f" (func $c2 "f")) + )) + ) + "resource types are not the same") + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f1")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f2")) + )) +) + +(component + (component $C1 + (type $X (resource (rep i32))) + (export $X1 "X1" (type $X)) + (export $X2 "X2" (type $X)) + + (core func $f (canon resource.drop $X)) + (func (export "f1") (param "X" (own $X1)) (canon lift (core func $f))) + (func (export "f2") (param "X" (own $X2)) (canon lift (core func $f))) + ) + (instance $c1 (instantiate $C1)) + + (component $C2 + (import "X" (type $X (sub resource))) + (import "f" (func (param "X" (own $X)))) + ) + (instance $c2 (instantiate $C2 + (with "X" (type $c1 "X1")) + (with "f" (func $c1 "f2")) + )) + (instance $c3 (instantiate $C2 + (with "X" (type $c1 "X2")) + (with "f" (func $c1 "f1")) + )) +) + +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (type $x u32) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected resource, found defined type") + +(assert_invalid + (component + (component $c + (type $t u32) + (import "x" (type (eq $t))) + ) + (type $x (resource (rep i32))) + (instance (instantiate $c (with "x" (type $x)))) + ) + "expected defined type, found resource") + +(assert_invalid + (component + (component $c + (import "x1" (type $x1 (sub resource))) + (import "x2" (type $x2 (eq $x1))) + ) + (type $x1 (resource (rep i32))) + (type $x2 (resource (rep i32))) + (instance (instantiate $c + (with "x1" (type $x1)) + (with "x2" (type $x2)) + )) + ) + "resource types are not the same") + +(component + (type $x (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c (instantiate $c (with "x" (type $x)))) + + (alias export $c "y" (type $x2)) + (core func (canon resource.rep $x2)) + +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (import "x" (func (result (own $r)))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type (component + (export "x" (type $x (sub resource))) + (import "f" (func (result (own $x)))) + )) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $r (resource (rep i32))) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) + ) + "func not valid to be used as export") + +;; direct exports count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (export $r "r" (type $r')) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; instances-as-a-bundle count as "explicit in" for resources +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (export $i "i" (instance $i')) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Transitive bundles count for "explicit in" +(component + (type $r' (resource (rep i32))) + (instance $i' + (export "r" (type $r')) + ) + (instance $i2' + (export "i" (instance $i')) + ) + (export $i2 "i2" (instance $i2')) + (alias export $i2 "i" (instance $i)) + (alias export $i "r" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Component instantiations count for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c' (instantiate $C (with "x" (type $r')))) + (export $c "c" (instance $c')) + (alias export $c "y" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Make sure threading things around is valid for "explicit in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (type $x (sub resource))) + (export "y" (type $x)) + ) + (instance $c (instantiate $C (with "x" (type $r')))) + (instance $i (export "x" (type $c "y"))) + + (component $C2 + (import "x" (instance $i + (export "i1" (instance + (export "i2" (type (sub resource))) + )) + )) + (export "y" (type $i "i1" "i2")) + ) + + (instance $i2 (export "i2" (type $i "x"))) + (instance $i1 (export "i1" (instance $i2))) + (instance $c2 (instantiate $C2 + (with "x" (instance $i1)) + )) + (export $r "x" (type $c2 "y")) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +;; Importing-and-exporting instances through instantiation counts for "explicit +;; in" +(component + (type $r' (resource (rep i32))) + (component $C + (import "x" (instance $x (export "t" (type (sub resource))))) + (export "y" (instance $x)) + ) + (instance $c' (instantiate $C + (with "x" (instance + (export "t" (type $r')) + )) + )) + (export $c "c" (instance $c')) + (alias export $c "y" (instance $y)) + (alias export $y "t" (type $r)) + + (core func $f (canon resource.drop $r)) + (func (export "f") (param "x" (own $r)) + (canon lift (core func $f))) +) + +(component definition + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i1 "f")) + )) + (instance (instantiate $c + (with "r" (type $i2 "r")) + (with "f" (func $i2 "f")) + )) +) + + +(assert_invalid + (component + (type $i (instance + (export "r" (type $r (sub resource))) + (export "f" (func (result (own $r)))) + )) + (import "i1" (instance $i1 (type $i))) + (import "i2" (instance $i2 (type $i))) + + (component $c + (import "r" (type $t (sub resource))) + (import "f" (func (result (own $t)))) + ) + (instance (instantiate $c + (with "r" (type $i1 "r")) + (with "f" (func $i2 "f")) + )) + ) + "resource types are not the same") + +;; substitution works +(component + (type $t (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (export "y" (type $t)) + ) + (instance $c1 (instantiate $c (with "x" (type $t)))) + (instance $c2 (instantiate $c (with "x" (type $t)))) + + (component $c2 + (import "x1" (type $t (sub resource))) + (import "x2" (type (eq $t))) + (import "x3" (type (eq $t))) + ) + (instance (instantiate $c2 + (with "x1" (type $t)) + (with "x2" (type $c1 "y")) + (with "x3" (type $c2 "y")) + )) +) + +;; must supply a resource to instantiation +(assert_invalid + (component + (component $c + (import "x" (type (sub resource))) + ) + (instance (instantiate $c)) + ) + "missing import named `x`") +(assert_invalid + (component + (type $x (resource (rep i32))) + (component $c + (import "x" (type (sub resource))) + (import "y" (type (sub resource))) + ) + (instance (instantiate $c (with "x" (type $x)))) + ) + "missing import named `y`") + +;; supply the wrong resource +(assert_invalid + (component + (type $x (resource (rep i32))) + (type $y (resource (rep i32))) + (component $c + (import "x" (type $t (sub resource))) + (import "y" (type (eq $t))) + ) + (instance (instantiate $c + (with "x" (type $x)) + (with "y" (type $y)) + )) + ) + "resource types are not the same") + +;; aliasing outer resources is ok +(component $A + (type $C (component + (import "x" (type $x (sub resource))) + + (type $y (component + (alias outer $C $x (type $my-x)) + (import "x" (type (eq $my-x))) + )) + + (import "y" (component (type $y))) + (export "z" (component (type $y))) + )) + + (type $t (resource (rep i32))) + + (alias outer $A $t (type $other-t)) + + (type (instance (export "t" (type (eq $t))))) + (type (component (export "t" (type (eq $t))))) + (type (component (import "t" (type (eq $t))))) +) + +;; aliasing beyond components, however, is not ok +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (component (alias outer $A $t (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (record (field "x" (own $t)))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (borrow $t)) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (export "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") +(assert_invalid + (component $A + (type $t (resource (rep i32))) + (type $u (component (import "a" (type (eq $t))))) + (component (alias outer $A $u (type $foo))) + ) + "refers to resources not defined in the current component") + +(assert_invalid + (component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (component (export "t" (type $t (sub resource))))) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + ) + "expected component, found instance") + +;; Show that two instantiations of the same component produce unique exported +;; resource types. +(assert_invalid + (component + (component $F + (type $t1 (resource (rep i32))) + (export "t1" (type $t1)) + ) + (instance $f1 (instantiate $F)) + (instance $f2 (instantiate $F)) + (alias export $f1 "t1" (type $t1)) + (alias export $f2 "t1" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) + ) + "type mismatch for import `y`") + +;; Show that re-exporting imported resources from an imported component doesn't +;; change the identity of that resource. +(component + (component $X + (type $t (resource (rep i32))) + (export "t" (type $t)) + ) + (component $F + (import "x" (instance $i (export "t" (type $t (sub resource))))) + (alias export $i "t" (type $t)) + (export "t" (type $t)) + ) + (instance $x1 (instantiate $X)) + (instance $f1 (instantiate $F (with "x" (instance $x1)))) + (instance $f2 (instantiate $F (with "x" (instance $x1)))) + (alias export $f1 "t" (type $t1)) + (alias export $f2 "t" (type $t2)) + (component $T + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance $test + (instantiate $T (with "x" (type $t1)) (with "y" (type $t2)))) +) + +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") + +;; validation of `[constructor]foo` +(assert_invalid + (component (import "[constructor]" (func))) + "not in kebab case") +(assert_invalid + (component (import "[constructor]a" (func))) + "should return one value") +(assert_invalid + (component (import "[constructor]a" (func (result u32)))) + "should return `(own $T)`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "import name `[constructor]a` is not valid") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) + "function does not match expected resource name `b`") +(assert_invalid + (component + (import "b" (type $a (sub resource))) + (import "[constructor]a" (func (result (result(own $a)))))) + "function does not match expected resource name `b`") +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (own $a))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result (own $a) (error string)))))) +(component definition + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (param "x" u32) (result (own $a))))) +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result string)))) + "function should return `(own $T)` or `(result (own $T))`") +(assert_invalid + (component + (import "a" (type $a (sub resource))) + (import "[constructor]a" (func (result (result string))))) + "function should return `(own $T)` or `(result (own $T))`") + +;; validation of `[method]a.b` +(assert_invalid + (component (import "[method]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[method]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[method].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[method]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[method]a.b" (func))) + "should have at least one argument") +(assert_invalid + (component (import "[method]a.b" (func (param "x" u32)))) + "should have a first argument called `self`") +(assert_invalid + (component (import "[method]a.b" (func (param "self" u32)))) + "should take a first argument of `(borrow $T)`") +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + "does not match expected resource name") +(component definition + (import "a" (type $T (sub resource))) + (import "[method]a.b" (func (param "self" (borrow $T))))) + +;; validation of `[static]a.b` +(assert_invalid + (component (import "[static]" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a" (func))) + "failed to find `.` character") +(assert_invalid + (component (import "[static]a." (func))) + "not in kebab case") +(assert_invalid + (component (import "[static].a" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b.c" (func))) + "not in kebab case") +(assert_invalid + (component (import "[static]a.b" (instance))) + "is not a func") +(assert_invalid + (component (import "[static]a.b" (func))) + "static resource name is not known in this context") + +(component definition + (import "a" (type (sub resource))) + (import "[static]a.b" (func))) + +;; exports/imports are disjoint +(assert_invalid + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export "[method]b.foo" (func $f)) + ) + "resource used in function does not have a name in this context") + +(component + (component + (import "b" (type $T (sub resource))) + (import "f" (func $f (param "self" (borrow $T)))) + (export $c "c" (type $T)) + (export "[method]c.foo" (func $f) (func (param "self" (borrow $c)))) + ) +) + +;; imports aren't transitive +(assert_invalid + (component + (import "i" (instance $i + (export "t" (type (sub resource))) + )) + (alias export $i "t" (type $t)) + (import "[method]t.foo" (func (param "self" (borrow $t)))) + ) + "resource used in function does not have a name in this context") + +;; validation happens in a type context +(assert_invalid + (component + (type (component + (import "b" (type $T (sub resource))) + (import "[constructor]a" (func (result (own $T)))) + )) + ) + "function does not match expected resource name `b`") + +;; bag-of-exports validation +(assert_invalid + (component + (type $T (resource (rep i32))) + (core module $m (func (export "a") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result (own $T)) (canon lift (core func $i "a"))) + (instance + (export "a" (type $T)) + (export "[constructor]a" (func $f)) + ) + ) + "resource used in function does not have a name in this context") + +(component + (component $C) + (instance (instantiate $C (with "this is not kebab case" (component $C)))) +) + +;; Test that unused arguments to instantiation are not validated to have +;; appropriate types with respect to kebab naming conventions which require +;; functions/interfaces/etc. +(component + (component $C) + (instance (instantiate $C (with "[method]foo.bar" (component $C)))) +) + +;; thread a resource through a few layers +(component + (component $C + (import "in" (type $r (sub resource))) + (export "out" (type $r)) + ) + + (type $r (resource (rep i32))) + + (instance $c1 (instantiate $C (with "in" (type $r)))) + (instance $c2 (instantiate $C (with "in" (type $c1 "out")))) + (instance $c3 (instantiate $C (with "in" (type $c2 "out")))) + (instance $c4 (instantiate $C (with "in" (type $c3 "out")))) + (instance $c5 (instantiate $C (with "in" (type $c4 "out")))) + + (component $C2 + (import "in1" (type $r (sub resource))) + (import "in2" (type (eq $r))) + (import "in3" (type (eq $r))) + (import "in4" (type (eq $r))) + (import "in5" (type (eq $r))) + (import "in6" (type (eq $r))) + ) + + (instance (instantiate $C2 + (with "in1" (type $r)) + (with "in2" (type $c1 "out")) + (with "in3" (type $c2 "out")) + (with "in4" (type $c3 "out")) + (with "in5" (type $c4 "out")) + (with "in6" (type $c5 "out")) + )) +) + +;; exporting an instance type "freshens" resources +(assert_invalid + (component + (import "x" (instance $i + (type $i (instance + (export "r" (type (sub resource))) + )) + (export "a" (instance (type $i))) + (export "b" (instance (type $i))) + )) + + (component $C + (import "x" (type $x (sub resource))) + (import "y" (type (eq $x))) + ) + (instance (instantiate $C + (with "x" (type $i "a" "r")) + (with "y" (type $i "b" "r")) + )) + ) + "resource types are not the same") + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + (alias export $t "r" (type $r)) + (type $t2' (instance + (export "r2" (type (eq $r))) + (export "r" (type (sub resource))) + )) + (export "t2" (instance (type $t2'))) + )) +) + +(component + (type (component + (type (instance + (export "bar" (type (sub resource))) + (export "[static]bar.a" (func)) + )) + (export "x" (instance (type 0))) + )) +) + +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (borrow $r)))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (list (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type (func (result (option (borrow $r))))) + ) + "function result cannot contain a `borrow` type") +(assert_invalid + (component + (type $r (resource (rep i32))) + (type $t (record (field "f" (borrow $r)))) + (type (func (result (option (list $t))))) + ) + "function result cannot contain a `borrow` type") + +;; forms of canon builtins +(component + (type $r (resource (rep i32))) + (core func (canon resource.new $r)) + (canon resource.new $r (core func)) + (core func (canon resource.drop $r)) + (canon resource.drop $r (core func)) + (core func (canon resource.rep $r)) + (canon resource.rep $r (core func)) +) diff --git a/test/wasm-tools/tags.wast b/test/wasm-tools/tags.wast new file mode 100644 index 00000000..5c70d3ab --- /dev/null +++ b/test/wasm-tools/tags.wast @@ -0,0 +1,30 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) + ) + "export `` for core instance 0 is not a tag") + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (alias core export $i "" (core tag $t)) +) + +(component + (core module $m (tag (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag $i "")))) + +(assert_invalid + (component + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance + (export "" (tag 0))) + ) + "unknown tag 0") diff --git a/test/wasm-tools/type-export-restrictions.wast b/test/wasm-tools/type-export-restrictions.wast new file mode 100644 index 00000000..d2971f8d --- /dev/null +++ b/test/wasm-tools/type-export-restrictions.wast @@ -0,0 +1,504 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +;; Test that unnamed types in various types are all detected + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "f" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (tuple $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (variant (case "c" $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (option $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (result $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Test that various types are all flagged as "requires a name" + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (enum "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (flags "a")) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (variant (case "a"))) + (type $f (list $t)) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; Some types don't need names +(component + (type $t1 (tuple (tuple u32))) + (export "t1" (type $t1)) + + (type $t2 (option (tuple (list u8) (result (list u32) (error (option string)))))) + (export "t2" (type $t2)) + + (type $t3 u32) + (export "t3" (type $t3)) +) + +(component + (type $t' (record (field "f" u32))) + (export $t "t" (type $t')) + (type $t2 (record (field "x" $t))) + (export "t2" (type $t2)) +) + +;; imports are validated as well +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (type (eq $t2))) + ) + "type not valid to be used as import") +(component + (type $t (record (field "f" u32))) + (import "t" (type $t' (eq $t))) + (type $t2 (record (field "f" $t'))) + (import "x" (type (eq $t2))) +) +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $t2 (record (field "f" $t))) + (import "x" (func (param "x" $t2))) + ) + "func not valid to be used as import") + +(assert_invalid + (component + (type $t (resource (rep i32))) + (export "t" (type $t)) + (type $f (list (own $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +;; validate within the type context +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) + ) + "func not valid to be used as export") +(assert_invalid + (component + (type (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + ) + "type not valid to be used as export") + +;; instances of unexported types is ok +(component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance + (export "f" (type $f)) + ) +) +;; .. but exporting them is not +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (instance $i + (export "f" (type $f)) + ) + (export "i" (instance $i)) + ) + "instance not valid to be used as export") + +;; Can't export a lifted function with unexported types +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $f) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Unexported instances don't work +(assert_invalid + (component + (type $t' (record (field "f" u32))) + (instance $i + (export "t" (type $t')) + ) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; Even through a component it doesn't work +(assert_invalid + (component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i (instantiate $C)) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) + ) + "func not valid to be used as export") + +;; through exported instances is ok though +(component + (type $t' (record (field "f" u32))) + (instance $i' + (export "t" (type $t')) + ) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) +(component + (component $C + (type $t (record (field "f" u32))) + (export "t" (type $t)) + ) + (instance $i' (instantiate $C)) + (export $i "i" (instance $i')) + (alias export $i "t" (type $t)) + + (core module $m (func $f (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "f" $t) (canon lift (core func $i "f"))) + (export "f" (func $f)) +) + +;; a type-ascribed export which is otherwise invalid can become valid +(component + (type $t (record (field "f" u32))) + + (core module $m (func (export "f") (param i32))) + (core instance $i (instantiate $m)) + (func $f (param "x" $t) (canon lift (core func $i "f"))) + + (export $t' "t" (type $t)) + (export "f" (func $f) (func (param "x" $t'))) +) + +;; imports can't reference exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (import "i" (func (result $t2))) + ) + "func not valid to be used as import") + +;; exports can reference imports +(component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (export "e-t1" (type $t2)) +) +(component + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (import "i" (func $f (result $t2))) + + (export "e-i" (func $f)) + ) +) + +;; outer aliases don't work for imports/exports +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (import "t1" (type $t2 (eq $t1))) + (component + (import "i" (func $f (result $t2))) + ) + ) + "func not valid to be used as import") +(assert_invalid + (component + (type $t1 (record (field "f" u32))) + (export $t2 "t1" (type $t1)) + (component + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (export "i") (result $t2) (canon lift (core func $i "f"))) + ) + ) + "func not valid to be used as export") + +;; outer aliases work for components, modules, and resources +(component + (type $c (component)) + (type (component + (import "c" (component (type $c))) + )) + (component + (import "c" (component (type $c))) + ) + (type $i (instance)) + (type (component + (import "c" (instance (type $i))) + )) + + (type $r (resource (rep i32))) + (type (component + (import "r" (type (eq $r))) + )) +) + +;; reexport of an import is fine +(component + (component + (import "r" (func $r)) + (export "r2" (func $r)) + ) +) +(component + (type $t (record (field "f" u32))) + (import "r" (type $r (eq $t))) + (export "r2" (type $r)) +) +(component + (import "r" (instance $r)) + (export "r2" (instance $r)) +) +(component definition + (import "r" (type $r (sub resource))) + (export "r2" (type $r)) +) + +;; bag of exports cannot be exported by carrying through context that's not +;; otherwise exported +(assert_invalid + (component + (component $A + (type $t (record (field "f" u32))) + (export $t2 "t" (type $t)) + (core module $m (func (export "f") (result i32) unreachable)) + (core instance $i (instantiate $m)) + (func $f (result $t2) (canon lift (core func $i "f"))) + + (instance (export "i") + (export "f" (func $f)) + ) + ) + + (instance $a (instantiate $A)) + ;; this component only exports `f`, not the record type that is the result + ;; of `f`, so it should be invalid. + (export "a" (instance $a "i")) + ) + "instance not valid to be used as export") + +;; instance types can be "temporarily invalid", but not if they're attached +;; to a concrete component +(component + (type (instance + (type $t (record (field "f" u32))) + (export "f" (func (param "x" $t))) + )) +) +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (instance (type $i))) + ) + "instance not valid to be used as import") + +;; allow for one import to refer to another +(component definition $C + (import "foo" (instance $i + (type $baz' (record (field "f" u32))) + (export "baz" (type $baz (eq $baz'))) + (type $bar' (record (field "baz" $baz))) + (export "bar" (type $bar (eq $bar'))) + )) + (alias export $i "bar" (type $bar)) + (import "bar" (instance + (alias outer $C $bar (type $bar')) + (export "bar" (type $bar (eq $bar'))) + (export "a" (func $f (result $bar))) + )) +) + +;; allow for one import to refer to another +(component + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (component $C + (type $r' (record (field "f" u32))) + (import "r" (type $r (eq $r'))) + (type $r2' (record (field "r" $r))) + (export "r2" (type $r2')) + ) + (instance $c (instantiate $C (with "r" (type $r)))) + (export "r2" (type $c "r2")) +) + +;; types are validated when they are exported +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (import "f" (type (eq $i))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $i (instance + (type $t (record (field "f" u32))) + (type $f (record (field "t" $t))) + (export "f" (type (eq $f))) + )) + (export "f" (type $i)) + ) + "type not valid to be used as export") + +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (import "f" (type (eq $f))) + ) + "type not valid to be used as import") +(assert_invalid + (component + (type $t (record (field "f" u32))) + (type $f (func (result $t))) + (export "f" (type $f)) + ) + "type not valid to be used as export") + +(component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component + (type (;0;) + (instance + (type (;0;) (enum "qux")) + (export (;1;) "baz" (type (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (export (;3;) "foo" (type (eq 2))) + ) + ) + (import (interface "demo:component/types") (instance (;0;) (type 0))) + (component (;0;) + (type (;0;) (enum "qux")) + (import "import-type-baz" (type (;1;) (eq 0))) + (type (;2;) (record (field "bar" 1) )) + (import "import-type-bar" (type (;3;) (eq 2))) + (export (;4;) "foo" (type 3)) + ) + (instance (;1;) (instantiate 0 + (with "import-type-baz" (type 0 "baz")) + (with "import-type-bar" (type 0 "foo")) + ) + ) + (export (;0;) (interface "demo:component/types") (instance 1)) + ) + (instance (instantiate 0 (with "demo:component/types" (instance 0)))) + (export (interface "demo:component/types") (instance 1 "demo:component/types")) +) diff --git a/test/wasm-tools/types.wast b/test/wasm-tools/types.wast new file mode 100644 index 00000000..5df1ec9d --- /dev/null +++ b/test/wasm-tools/types.wast @@ -0,0 +1,374 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component + (type $t (instance)) + (import "a" (func (type $t))) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (core type $t (func)) + (import "a" (core module (type $t))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (func)) + (import "a" (instance (type $t))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (type $t (func)) + (type (component + (import "a" (instance (type $t))) + )) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $t (func)) + (type (component + (import "a" (core module (type $t))) + )) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $t (instance)) + (type (component + (import "a" (func (type $t))) + )) + ) + "type index 0 is not a function type") + +(assert_invalid + (component + (export "a" (core module 0)) + ) + "module index out of bounds") + +(assert_invalid + (component + (export "a" (instance 0)) + ) + "instance index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (core type (module + (export "a" (func)) + (export "a" (func)) + )) + ) + "export name `a` already defined") + +(assert_invalid + (component + (core type (module + (import "" "" (func)) + (import "" "" (func)) + )) + ) + "duplicate import name") + +(assert_invalid + (component + (core type (module + (import "" "" (memory 70000)) + )) + ) + "memory size must be at most") + +(assert_invalid + (component + (type (component + (export "a" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (component + (export "a" (func)) + (export "A" (func)) + )) + ) + "export name `A` conflicts with previous name `a`") + +(assert_invalid + (component + (type (component + (import "A" (func)) + (import "a" (func)) + )) + ) + "import name `a` conflicts with previous name `A`") + +(assert_malformed + (component quote + "(component $c (core type $t (module (alias outer $c $t (type)))))" + ) + "unknown core type") + +(assert_invalid + (component + (core type (module + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(component $c + (core type $f (func)) + (core type $t (module + (alias outer $c $f (type)) + )) +) + +(assert_malformed + (component quote + "(component $c (type $t (component (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (component + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (component + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component + (type (instance + (export "" (func (type 0))) + )) + ) + "type index out of bounds") + +(assert_invalid + (component + (type (instance + (export "foo-BAR-baz" (func)) + (export "FOO-bar-BAZ" (func)) + )) + ) + "export name `FOO-bar-BAZ` conflicts with previous name `foo-BAR-baz`") + +(assert_malformed + (component quote + "(component $c (type $t (instance (alias outer $c $t (type)))))" + ) + "unknown type") + +(assert_invalid + (component + (type (instance + (alias outer 1 0 (type)) + )) + ) + "type index out of bounds") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (alias outer 100 0 (type)) + )) + ) + "invalid outer alias count of 100") + +(assert_invalid + (component $c + (type $f (func)) + (type $t (instance + (core type (module + (export "" (func)) + (export "" (func)) + )) + )) + ) + "name `` already defined") + +(assert_invalid + (component $c + (type $f (func (param "" string))) + ) + "function parameter name cannot be empty") + +(component + (type $t (func (result (tuple (list u8) u32)))) +) + +(component $C + (core type $t (func)) + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) +) + +(component $C + (component $C2 + (core type $t (func)) + (core type (module + (alias outer $C2 $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component $C + (core type $t (func)) + (component $C2 + (core type (module + (alias outer $C $t (type $a)) + (import "" "" (func (type $a))) + )) + ) +) + +(component + (type (instance + (type string) + (export "a" (type (eq 0))) + )) +) + +(component + (type (component + (type string) + (import "a" (type (eq 0))) + (export "b" (type (eq 0))) + )) +) + +(assert_invalid + (component + (type (variant)) + ) + "variant type must have at least one case") + +(assert_invalid + (component + (type (enum)) + ) + "enum type must have at least one variant") + +(assert_invalid + (component + (type (record)) + ) + "record type must have at least one field") + +(assert_invalid + (component + (type (flags)) + ) + "flags must have at least one entry") + +(assert_invalid + (component + (type (tuple)) + ) + "tuple type must have at least one type") + +(component $c + (core type $f (func)) + (component $c2 + (core type $t (module + (alias outer $c $f (type)) + )) + ) +) + +(assert_invalid + (component + (type (flags + "f1" + "f2" + "f3" + "f4" + "f5" + "f6" + "f7" + "f8" + "f9" + "f10" + "f11" + "f12" + "f13" + "f14" + "f15" + "f16" + "f17" + "f18" + "f19" + "f20" + "f21" + "f22" + "f23" + "f24" + "f25" + "f26" + "f27" + "f28" + "f29" + "f30" + "f31" + "f32" + "f33" + )) + ) + "cannot have more than 32 flags") + +(assert_invalid + (component + (core type $t (module)) + (core type (func (param (ref $t)))) + ) + "type index 0 is a module type") + +(assert_invalid + (component + (core type (func (param (ref 100)))) + ) + "type index out of bounds") diff --git a/test/wasm-tools/very-nested.wast b/test/wasm-tools/very-nested.wast new file mode 100644 index 00000000..42c5aede --- /dev/null +++ b/test/wasm-tools/very-nested.wast @@ -0,0 +1,1954 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_invalid + (component $$esl + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c *****") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c t.*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "0*************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "00AGG554M******+*****e 4$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "anonmm-x23foinas-ASDOJASD") + ) + (component + (export "c t.****0*********") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "agds-ASF-TT-yy") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "0+AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00A$qq") + ) + (component + (export "c t.*************") + (export "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "15AG:GG!le*$$qq") + ) + (component + (export "c .t*") + (component + (export "c 3@EGGGG$qq**") + (export "bsdew2-sdbsdb") + ) + (component + (export "c t.********)*eleo &m Nx2GGGGle*$$qq") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "sdg-q12") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "jsjsjs") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E**************777777777777777777777777777777777777777777777777777777777777771.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E***0AG") + (component + (export "c 3@EGG*****+*****e $$qq") + ) + (component + (export "q**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c=t.*************") + (export "00AG") + (component + (export "alskgn-mbnaj4-a33i5nf") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "afhinds-T39OIDN-f1jsj11") + (import "sf-gqo3ngin23ogin13g-bvcad") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle '$$qq") + ) + (component + (export "q") + ) + (component + (export "b 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 0.*************") + (export "00AGGWGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*********GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E************[******") + (import "bsdew2-sdbsdb") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 6@E$*************7777777777777777777777777777777777777777777MM~MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM777777777777777777777777777777777777777777*****") + (import "00e*$$qq") + ) + (component + (export "EGG-y-GG-qq") + (export "00AGGG.Gle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "bsdew2-sdbsdb") + ) + (component + (export "c 1.*************") + (export "00AGGGGle A*$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGl4@E****\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*****GG$qq**") + (export "dojgn-ejs9-nd188") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + (component + (export "q") + ) + (component + (export "c 3@E*******77777777777777777777777777777777GG)le 0AGGGGle $$qq") + ) + (component + (export "q") + ) + (component + (export "c 3@E*******************") + (import "00CGGGGle*$$qq") + ) + (component + (export "c t.*************") + (export "00AGGGGle *$$qq") + ) + (component) + ) + ) + "conflicts with previous name") + +(assert_invalid + (component + (type $m0 (component)) + (type $m1 (component + (import "i1" (component (type $m0))) + (import "i2" (component (type $m0))) + (import "i3" (component (type $m0))) + (import "i4" (component (type $m0))) + (import "i5" (component (type $m0))) + (import "i6" (component (type $m0))) + (import "i7" (component (type $m0))) + (import "i8" (component (type $m0))) + (import "i9" (component (type $m0))) + (import "i10" (component (type $m0))) + )) + (type $m2 (component + (import "i1" (component (type $m1))) + (import "i2" (component (type $m1))) + (import "i3" (component (type $m1))) + (import "i4" (component (type $m1))) + (import "i5" (component (type $m1))) + (import "i6" (component (type $m1))) + (import "i7" (component (type $m1))) + (import "i8" (component (type $m1))) + (import "i9" (component (type $m1))) + (import "i10" (component (type $m1))) + )) + (type $m3 (component + (import "i1" (component (type $m2))) + (import "i2" (component (type $m2))) + (import "i3" (component (type $m2))) + (import "i4" (component (type $m2))) + (import "i5" (component (type $m2))) + (import "i6" (component (type $m2))) + (import "i7" (component (type $m2))) + (import "i8" (component (type $m2))) + (import "i9" (component (type $m2))) + (import "i10" (component (type $m2))) + )) + (type $m4 (component + (import "i1" (component (type $m3))) + (import "i2" (component (type $m3))) + (import "i3" (component (type $m3))) + (import "i4" (component (type $m3))) + (import "i5" (component (type $m3))) + (import "i6" (component (type $m3))) + (import "i7" (component (type $m3))) + (import "i8" (component (type $m3))) + (import "i9" (component (type $m3))) + (import "i10" (component (type $m3))) + )) + (type $m5 (component + (import "i1" (component (type $m4))) + (import "i2" (component (type $m4))) + (import "i3" (component (type $m4))) + (import "i4" (component (type $m4))) + (import "i5" (component (type $m4))) + (import "i6" (component (type $m4))) + (import "i7" (component (type $m4))) + (import "i8" (component (type $m4))) + (import "i9" (component (type $m4))) + (import "i10" (component (type $m4))) + )) + (type $m6 (component + (import "i1" (component (type $m5))) + (import "i2" (component (type $m5))) + (import "i3" (component (type $m5))) + (import "i4" (component (type $m5))) + (import "i5" (component (type $m5))) + (import "i6" (component (type $m5))) + (import "i7" (component (type $m5))) + (import "i8" (component (type $m5))) + (import "i9" (component (type $m5))) + (import "i10" (component (type $m5))) + )) + (type $m7 (component + (import "i1" (component (type $m6))) + (import "i2" (component (type $m6))) + (import "i3" (component (type $m6))) + (import "i4" (component (type $m6))) + (import "i5" (component (type $m6))) + (import "i6" (component (type $m6))) + (import "i7" (component (type $m6))) + (import "i8" (component (type $m6))) + (import "i9" (component (type $m6))) + (import "i10" (component (type $m6))) + )) + (type $m8 (component + (import "i1" (component (type $m7))) + (import "i2" (component (type $m7))) + (import "i3" (component (type $m7))) + (import "i4" (component (type $m7))) + (import "i5" (component (type $m7))) + (import "i6" (component (type $m7))) + (import "i7" (component (type $m7))) + (import "i8" (component (type $m7))) + (import "i9" (component (type $m7))) + (import "i10" (component (type $m7))) + )) + (type $m9 (component + (import "i1" (component (type $m8))) + (import "i2" (component (type $m8))) + (import "i3" (component (type $m8))) + (import "i4" (component (type $m8))) + (import "i5" (component (type $m8))) + (import "i6" (component (type $m8))) + (import "i7" (component (type $m8))) + (import "i8" (component (type $m8))) + (import "i9" (component (type $m8))) + (import "i10" (component (type $m8))) + )) + + (type $m (component + (import "a" (component (type $m9))) + )) + (import "a" (component $a (type $m9))) + (import "b" (component $b (type $m))) + (instance (instantiate $b (with "a" (component $a)))) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + (component $m0) + (component $m1 + (instance (export "e0") (instantiate $m0)) + (instance (export "e1") (instantiate $m0)) + (instance (export "e2") (instantiate $m0)) + (instance (export "e3") (instantiate $m0)) + (instance (export "e4") (instantiate $m0)) + (instance (export "e5") (instantiate $m0)) + (instance (export "e6") (instantiate $m0)) + (instance (export "e7") (instantiate $m0)) + (instance (export "e8") (instantiate $m0)) + (instance (export "e9") (instantiate $m0)) + ) + (component $m2 + (instance (export "e0") (instantiate $m1)) + (instance (export "e1") (instantiate $m1)) + (instance (export "e2") (instantiate $m1)) + (instance (export "e3") (instantiate $m1)) + (instance (export "e4") (instantiate $m1)) + (instance (export "e5") (instantiate $m1)) + (instance (export "e6") (instantiate $m1)) + (instance (export "e7") (instantiate $m1)) + (instance (export "e8") (instantiate $m1)) + (instance (export "e9") (instantiate $m1)) + ) + (component $m3 + (instance (export "e0") (instantiate $m2)) + (instance (export "e1") (instantiate $m2)) + (instance (export "e2") (instantiate $m2)) + (instance (export "e3") (instantiate $m2)) + (instance (export "e4") (instantiate $m2)) + (instance (export "e5") (instantiate $m2)) + (instance (export "e6") (instantiate $m2)) + (instance (export "e7") (instantiate $m2)) + (instance (export "e8") (instantiate $m2)) + (instance (export "e9") (instantiate $m2)) + ) + (component $m4 + (instance (export "e0") (instantiate $m3)) + (instance (export "e1") (instantiate $m3)) + (instance (export "e2") (instantiate $m3)) + (instance (export "e3") (instantiate $m3)) + (instance (export "e4") (instantiate $m3)) + (instance (export "e5") (instantiate $m3)) + (instance (export "e6") (instantiate $m3)) + (instance (export "e7") (instantiate $m3)) + (instance (export "e8") (instantiate $m3)) + (instance (export "e9") (instantiate $m3)) + ) + (component $m5 + (instance (export "e0") (instantiate $m4)) + (instance (export "e1") (instantiate $m4)) + (instance (export "e2") (instantiate $m4)) + (instance (export "e3") (instantiate $m4)) + (instance (export "e4") (instantiate $m4)) + (instance (export "e5") (instantiate $m4)) + (instance (export "e6") (instantiate $m4)) + (instance (export "e7") (instantiate $m4)) + (instance (export "e8") (instantiate $m4)) + (instance (export "e9") (instantiate $m4)) + ) + (component $m6 + (instance (export "e0") (instantiate $m5)) + (instance (export "e1") (instantiate $m5)) + (instance (export "e2") (instantiate $m5)) + (instance (export "e3") (instantiate $m5)) + (instance (export "e4") (instantiate $m5)) + (instance (export "e5") (instantiate $m5)) + (instance (export "e6") (instantiate $m5)) + (instance (export "e7") (instantiate $m5)) + (instance (export "e8") (instantiate $m5)) + (instance (export "e9") (instantiate $m5)) + ) + (component $m7 + (instance (export "e0") (instantiate $m6)) + (instance (export "e1") (instantiate $m6)) + (instance (export "e2") (instantiate $m6)) + (instance (export "e3") (instantiate $m6)) + (instance (export "e4") (instantiate $m6)) + (instance (export "e5") (instantiate $m6)) + (instance (export "e6") (instantiate $m6)) + (instance (export "e7") (instantiate $m6)) + (instance (export "e8") (instantiate $m6)) + (instance (export "e9") (instantiate $m6)) + ) + ) + "effective type size exceeds the limit") + +(assert_invalid + (component + ;; size(t0) == 1 + (type $t0 (flags "x")) + + ;; size(t1) == 10 + (type $t1 (record + (field "f0" $t0) + (field "f1" $t0) + (field "f2" $t0) + (field "f3" $t0) + (field "f4" $t0) + (field "f5" $t0) + (field "f6" $t0) + (field "f7" $t0) + (field "f8" $t0) + (field "f9" $t0) + )) + + ;; size(t2) == 100 + (type $t2 (record + (field "f0" $t1) + (field "f1" $t1) + (field "f2" $t1) + (field "f3" $t1) + (field "f4" $t1) + (field "f5" $t1) + (field "f6" $t1) + (field "f7" $t1) + (field "f8" $t1) + (field "f9" $t1) + )) + + ;; size(t3) == 1000 + (type $t3 (record + (field "f0" $t2) + (field "f1" $t2) + (field "f2" $t2) + (field "f3" $t2) + (field "f4" $t2) + (field "f5" $t2) + (field "f6" $t2) + (field "f7" $t2) + (field "f8" $t2) + (field "f9" $t2) + )) + + ;; size(t4) == 10000 + (type $t4 (record + (field "f0" $t3) + (field "f1" $t3) + (field "f2" $t3) + (field "f3" $t3) + (field "f4" $t3) + (field "f5" $t3) + (field "f6" $t3) + (field "f7" $t3) + (field "f8" $t3) + (field "f9" $t3) + )) + + ;; size(t5) == 100000 + (type $t5 (record + (field "f0" $t4) + (field "f1" $t4) + (field "f2" $t4) + (field "f3" $t4) + (field "f4" $t4) + (field "f5" $t4) + (field "f6" $t4) + (field "f7" $t4) + (field "f8" $t4) + (field "f9" $t4) + )) + + (type $f (func + (param "a" $t5) + (param "b" $t5) + (param "c" $t5) + (param "d" $t5) + (param "e" $t5) + (param "f" $t5) + (param "g" $t5) + (param "h" $t5) + (param "i" $t5) + (param "j" $t5) + )) + ) + "effective type size exceeds the limit") + +(assert_malformed + (component quote + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + "(component(component(component(component(component(component(component" + ) + "nesting too deep") diff --git a/test/wasm-tools/virtualize.wast b/test/wasm-tools/virtualize.wast new file mode 100644 index 00000000..d60b73b9 --- /dev/null +++ b/test/wasm-tools/virtualize.wast @@ -0,0 +1,119 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(component + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + (core instance $libc (instantiate $libc)) + + (component $child + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "count" u32) (result (list u8)))) + (export "write" (func (param "bytes" (list u8)) (result u32))) + )) + + (core instance $libc (instantiate $libc)) + + (core module $m + (import "wasi-file" "read" (func $read (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core func $wasi_file_read + (canon lower (func $wasi-file "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $i (instantiate $m + (with "wasi-file" (instance + (export "read" (func $wasi_file_read)) + )) + )) + + (func (export "play") + (canon lift (core func $i "play")) + ) + ) + + (component $virtualize + (import "wasi-file" (instance $wasi-file + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (export "read" (func $wasi-file "read")) + (export "write" (func $wasi-file "write")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + (import "virtualize" (component $VIRTUALIZE + (import "wasi-file" (instance (type $WasiFile))) + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "child" (component $CHILD + (import "wasi-file" (instance (type $WasiFile))) + (export "play" (func)) + ) + ) + + (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance $real-wasi)))) + (instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + + (export "work" (func $child "play")) + ) + + (component + (type $WasiFile (instance + (export "read" (func (param "len" u32) (result (list u8)))) + (export "write" (func (param "buf" (list u8)) (result u32))) + )) + (import "wasi-file" (instance $real-wasi (type $WasiFile))) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi-file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi-file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi-file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi-file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory $libc "mem") + (realloc (func $libc "realloc")) + ) + ) + ) +) diff --git a/test/wasm-tools/wrong-order.wast b/test/wasm-tools/wrong-order.wast new file mode 100644 index 00000000..098fc419 --- /dev/null +++ b/test/wasm-tools/wrong-order.wast @@ -0,0 +1,11 @@ +;; RUN: wast --assert default --snapshot tests/snapshots % + +(assert_malformed + (module binary + "\00asm\01\00\00\00" + + "\01\01\00" ;; type section, 1 byte, 0 entries + "\0b\01\00" ;; data section, 1 byte, 0 entries + "\01\01\00" ;; type section, 1 byte, 0 entries + ) + "section out of order") diff --git a/test/wasmtime/adapter.wast b/test/wasmtime/adapter.wast new file mode 100644 index 00000000..0ca70a1d --- /dev/null +++ b/test/wasmtime/adapter.wast @@ -0,0 +1,137 @@ +;;! multi_memory = true + +;; basic function lifting +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") + (canon lift (core func $i "")) + ) +) + +;; use an aliased type +(component $c + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (type $to_alias (func)) + (alias outer $c $to_alias (type $alias)) + + (func (export "thunk") (type $alias) + (canon lift (core func $i "")) + ) +) + +;; test out some various canonical abi +(component $c + (core module $m + (func (export "") (param i32 i32)) + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $i (instantiate $m)) + + (func (export "thunk") (param "a" string) + (canon lift + (core func $i "") + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk8") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf8 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunk16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) + + (func (export "thunklatin16") (param "a" string) + (canon lift + (core func $i "") + string-encoding=latin1+utf16 + (memory $i "memory") + (realloc (func $i "realloc")) + ) + ) +) + +;; lower something then immediately lift it +(component $c + (import "host-return-two" (func $f (result u32))) + + (core func $f_lower + (canon lower (func $f)) + ) + (func $f2 (result s32) + (canon lift (core func $f_lower)) + ) + (export "f" (func $f2)) +) + +;; valid, but odd +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) +) +(assert_trap + (component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + + (func $f1 (canon lift (core func $m ""))) + (core func $f2 (canon lower (func $f1))) + + (core module $m2 + (import "" "" (func $f)) + (func $start + call $f) + (start $start) + ) + (core instance (instantiate $m2 + (with "" (instance (export "" (func $f2)))) + )) + ) + "degenerate component adapter called") + +;; fiddling with 0-sized lists +(component $c + (core module $m + (func (export "x") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const -1) + (memory (export "memory") 0) + ) + (core instance $m (instantiate $m)) + (type $t' (result)) + (export $t "t" (type $t')) + (func $f (param "a" (list $t)) + (canon lift + (core func $m "x") + (realloc (func $m "realloc")) + (memory $m "memory") + ) + ) + (export "empty-list" (func $f)) +) +(assert_trap (invoke "empty-list" (list.const)) "realloc return: beyond end of memory") diff --git a/test/wasmtime/aliasing.wast b/test/wasmtime/aliasing.wast new file mode 100644 index 00000000..ad18f935 --- /dev/null +++ b/test/wasmtime/aliasing.wast @@ -0,0 +1,29 @@ +(component + (component + (component + (component) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + (instance (instantiate 0)) + (export "a" (instance 0)) + ) + + (instance (instantiate 0)) ;; instance 0 + (alias export 0 "a" (instance)) ;; instance 1 + (export "a" (instance 1)) ;; instance 2 + (alias export 2 "a" (instance)) ;; instance 3 + (export "inner-a" (instance 3)) ;; instance 4 +) + +(component + (component + (core module) + (export "a" (core module 0)) + ) + + (instance (instantiate 0)) + (alias export 0 "a" (core module)) ;; module 0 + (export "a" (core module 0)) ;; module 1 + (core instance (instantiate 1)) +) diff --git a/test/wasmtime/fused.wast b/test/wasmtime/fused.wast new file mode 100644 index 00000000..90f2ed4a --- /dev/null +++ b/test/wasmtime/fused.wast @@ -0,0 +1,1359 @@ +;;! multi_memory = true + +;; smoke test with no arguments and no results +(component + (core module $m + (func (export "")) + ) + (core instance $m (instantiate $m)) + (func $foo (canon lift (core func $m ""))) + + (component $c + (import "a" (func $foo)) + + (core func $foo (canon lower (func $foo))) + (core module $m2 + (import "" "" (func)) + (start 0) + ) + (core instance $m2 (instantiate $m2 (with "" (instance (export "" (func $foo)))))) + ) + + (instance $c (instantiate $c (with "a" (func $foo)))) +) + +;; boolean parameters +(component + (core module $m + (func (export "assert_true") (param i32) + local.get 0 + i32.const 1 + i32.eq + i32.eqz + if unreachable end + ) + (func (export "assert_false") (param i32) + local.get 0 + if unreachable end + ) + (func (export "ret-bool") (param i32) (result i32) + local.get 0 + ) + ) + (core instance $m (instantiate $m)) + (func $assert_true (param "a" bool) (canon lift (core func $m "assert_true"))) + (func $assert_false (param "a" bool) (canon lift (core func $m "assert_false"))) + (func $ret_bool (param "a" u32) (result bool) (canon lift (core func $m "ret-bool"))) + + (component $c + (import "assert-true" (func $assert_true (param "a" bool))) + (import "assert-false" (func $assert_false (param "a" bool))) + (import "ret-bool" (func $ret_bool (param "a" u32) (result bool))) + + (core func $assert_true (canon lower (func $assert_true))) + (core func $assert_false (canon lower (func $assert_false))) + (core func $ret_bool (canon lower (func $ret_bool))) + + (core module $m2 + (import "" "assert-true" (func $assert_true (param i32))) + (import "" "assert-false" (func $assert_false (param i32))) + (import "" "ret-bool" (func $ret_bool (param i32) (result i32))) + + (func $start + (call $assert_true (i32.const 1)) + (call $assert_true (i32.const 2)) + (call $assert_true (i32.const -1)) + (call $assert_false (i32.const 0)) + + (if (i32.ne (call $ret_bool (i32.const 1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 2)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const -1)) (i32.const 1)) + (then (unreachable))) + (if (i32.ne (call $ret_bool (i32.const 0)) (i32.const 0)) + (then (unreachable))) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "" (instance + (export "assert-true" (func $assert_true)) + (export "assert-false" (func $assert_false)) + (export "ret-bool" (func $ret_bool)) + )) + )) + ) + + (instance $c (instantiate $c + (with "assert-true" (func $assert_true)) + (with "assert-false" (func $assert_false)) + (with "ret-bool" (func $ret_bool)) + )) +) + +;; lots of parameters and results +(component + (type $roundtrip (func + ;; 20 u32 params + (param "a1" u32) (param "a2" u32) (param "a3" u32) (param "a4" u32) (param "a5" u32) + (param "a6" u32) (param "a7" u32) (param "a8" u32) (param "a9" u32) (param "a10" u32) + (param "a11" u32) (param "a12" u32) (param "a13" u32) (param "a14" u32) (param "a15" u32) + (param "a16" u32) (param "a17" u32) (param "a18" u32) (param "a19" u32) (param "a20" u32) + + ;; 10 u32 results + (result (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + )) + + (core module $m + (memory (export "memory") 1) + (func (export "roundtrip") (param $src i32) (result i32) + (local $dst i32) + (if (i32.ne (local.get $src) (i32.const 16)) + (then (unreachable))) + + (if (i32.ne (i32.load offset=0 (local.get $src)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $src)) (i32.const 2)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $src)) (i32.const 3)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $src)) (i32.const 4)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $src)) (i32.const 5)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $src)) (i32.const 6)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $src)) (i32.const 7)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $src)) (i32.const 8)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $src)) (i32.const 9)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $src)) (i32.const 10)) (then (unreachable))) + (if (i32.ne (i32.load offset=40 (local.get $src)) (i32.const 11)) (then (unreachable))) + (if (i32.ne (i32.load offset=44 (local.get $src)) (i32.const 12)) (then (unreachable))) + (if (i32.ne (i32.load offset=48 (local.get $src)) (i32.const 13)) (then (unreachable))) + (if (i32.ne (i32.load offset=52 (local.get $src)) (i32.const 14)) (then (unreachable))) + (if (i32.ne (i32.load offset=56 (local.get $src)) (i32.const 15)) (then (unreachable))) + (if (i32.ne (i32.load offset=60 (local.get $src)) (i32.const 16)) (then (unreachable))) + (if (i32.ne (i32.load offset=64 (local.get $src)) (i32.const 17)) (then (unreachable))) + (if (i32.ne (i32.load offset=68 (local.get $src)) (i32.const 18)) (then (unreachable))) + (if (i32.ne (i32.load offset=72 (local.get $src)) (i32.const 19)) (then (unreachable))) + (if (i32.ne (i32.load offset=76 (local.get $src)) (i32.const 20)) (then (unreachable))) + + (local.set $dst (i32.const 500)) + + (i32.store offset=0 (local.get $dst) (i32.const 21)) + (i32.store offset=4 (local.get $dst) (i32.const 22)) + (i32.store offset=8 (local.get $dst) (i32.const 23)) + (i32.store offset=12 (local.get $dst) (i32.const 24)) + (i32.store offset=16 (local.get $dst) (i32.const 25)) + (i32.store offset=20 (local.get $dst) (i32.const 26)) + (i32.store offset=24 (local.get $dst) (i32.const 27)) + (i32.store offset=28 (local.get $dst) (i32.const 28)) + (i32.store offset=32 (local.get $dst) (i32.const 29)) + (i32.store offset=36 (local.get $dst) (i32.const 30)) + + local.get $dst + ) + + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 16) + ) + (core instance $m (instantiate $m)) + + (func $roundtrip (type $roundtrip) + (canon lift (core func $m "roundtrip") (memory $m "memory") + (realloc (func $m "realloc"))) + ) + + (component $c + (import "roundtrip" (func $roundtrip (type $roundtrip))) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $roundtrip + (canon lower (func $roundtrip) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m2 + (import "libc" "memory" (memory 1)) + (import "" "roundtrip" (func $roundtrip (param i32 i32))) + + (func $start + (local $addr i32) + (local $retaddr i32) + + (local.set $addr (i32.const 100)) + (call $store_many (i32.const 20) (local.get $addr)) + + (local.set $retaddr (i32.const 200)) + (call $roundtrip (local.get $addr) (local.get $retaddr)) + + (if (i32.ne (i32.load offset=0 (local.get $retaddr)) (i32.const 21)) (then (unreachable))) + (if (i32.ne (i32.load offset=4 (local.get $retaddr)) (i32.const 22)) (then (unreachable))) + (if (i32.ne (i32.load offset=8 (local.get $retaddr)) (i32.const 23)) (then (unreachable))) + (if (i32.ne (i32.load offset=12 (local.get $retaddr)) (i32.const 24)) (then (unreachable))) + (if (i32.ne (i32.load offset=16 (local.get $retaddr)) (i32.const 25)) (then (unreachable))) + (if (i32.ne (i32.load offset=20 (local.get $retaddr)) (i32.const 26)) (then (unreachable))) + (if (i32.ne (i32.load offset=24 (local.get $retaddr)) (i32.const 27)) (then (unreachable))) + (if (i32.ne (i32.load offset=28 (local.get $retaddr)) (i32.const 28)) (then (unreachable))) + (if (i32.ne (i32.load offset=32 (local.get $retaddr)) (i32.const 29)) (then (unreachable))) + (if (i32.ne (i32.load offset=36 (local.get $retaddr)) (i32.const 30)) (then (unreachable))) + ) + + (func $store_many (param $amt i32) (param $addr i32) + (local $c i32) + (loop $loop + (local.set $c (i32.add (local.get $c) (i32.const 1))) + (i32.store (local.get $addr) (local.get $c)) + (local.set $addr (i32.add (local.get $addr) (i32.const 4))) + + (if (i32.ne (local.get $amt) (local.get $c)) (then (br $loop))) + ) + ) + (start $start) + ) + (core instance $m2 (instantiate $m2 + (with "libc" (instance $libc)) + (with "" (instance (export "roundtrip" (func $roundtrip)))) + )) + ) + + (instance $c (instantiate $c + (with "roundtrip" (func $roundtrip)) + )) +) + +;; this will require multiple adapter modules to get generated +(component + (core module $root (func (export "") (result i32) + i32.const 0 + )) + (core instance $root (instantiate $root)) + (func $root (result u32) (canon lift (core func $root ""))) + + (component $c + (import "thunk" (func $import (result u32))) + (core func $import (canon lower (func $import))) + (core module $reexport + (import "" "" (func $thunk (result i32))) + (func (export "thunk") (result i32) + call $thunk + i32.const 1 + i32.add) + ) + (core instance $reexport (instantiate $reexport + (with "" (instance + (export "" (func $import)) + )) + )) + (func $export (export "thunk2") (result u32) + (canon lift (core func $reexport "thunk")) + ) + ) + + (instance $c1 (instantiate $c (with "thunk" (func $root)))) + (instance $c2 (instantiate $c (with "thunk" (func $c1 "thunk2")))) + (instance $c3 (instantiate $c (with "thunk" (func $c2 "thunk2")))) + (instance $c4 (instantiate $c (with "thunk" (func $c3 "thunk2")))) + (instance $c5 (instantiate $c (with "thunk" (func $c4 "thunk2")))) + (instance $c6 (instantiate $c (with "thunk" (func $c5 "thunk2")))) + + (component $verify + (import "thunk" (func $thunk (result u32))) + (core func $thunk (canon lower (func $thunk))) + (core module $verify + (import "" "" (func $thunk (result i32))) + + (func $start + call $thunk + i32.const 6 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify + (with "" (instance + (export "" (func $thunk)) + )) + )) + ) + (instance (instantiate $verify (with "thunk" (func $c6 "thunk2")))) +) + +;; Fancy case of an adapter using an adapter. Note that this is silly and +;; doesn't actually make any sense at runtime, we just shouldn't panic on a +;; valid component. +(component + (type $tuple20 (tuple + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32 + u32 u32 u32 u32 u32)) + + (component $realloc + (core module $realloc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $realloc (instantiate $realloc)) + (func $realloc (param "a" (tuple u32 u32 u32 u32)) (result u32) + (canon lift (core func $realloc "realloc")) + ) + (export "realloc" (func $realloc)) + ) + (instance $realloc (instantiate $realloc)) + (core func $realloc (canon lower (func $realloc "realloc"))) + + (core module $m + (memory (export "memory") 1) + (func (export "foo") (param i32)) + ) + (core instance $m (instantiate $m)) + (func $foo (param "a" $tuple20) + (canon lift + (core func $m "foo") + (memory $m "memory") + (realloc (func $realloc)) + ) + ) + + (component $c + (import "foo" (func $foo (param "a" $tuple20))) + + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $foo + (canon lower (func $foo) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + (core module $something + (import "" "foo" (func (param i32))) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c + (with "foo" (func $foo)) + )) +) + +;; Don't panic or otherwise create extraneous adapter modules when the same +;; adapter is used twice for a module's argument. +(component + (core module $m + (func (export "foo") (param)) + ) + (core instance $m (instantiate $m)) + (func $foo (canon lift (core func $m "foo"))) + + (component $c + (import "foo" (func $foo)) + (core func $foo (canon lower (func $foo))) + + (core module $something + (import "" "a" (func)) + (import "" "b" (func)) + ) + (core instance (instantiate $something + (with "" (instance + (export "a" (func $foo)) + (export "b" (func $foo)) + )) + )) + ) + (instance (instantiate $c (with "foo" (func $foo)))) +) + +;; post-return should get invoked by the generated adapter, if specified +(component + (core module $m + (global $post_called (mut i32) (i32.const 0)) + (func (export "foo") + ;; assert `foo-post` not called yet + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ) + (func (export "foo-post") + ;; assert `foo-post` not called before + global.get $post_called + i32.const 1 + i32.eq + if unreachable end + ;; ... then flag as called + i32.const 1 + global.set $post_called + ) + (func (export "assert-post") + global.get $post_called + i32.const 1 + i32.ne + if unreachable end + ) + ) + (core instance $m (instantiate $m)) + (func $foo (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + (func $assert_post (canon lift (core func $m "assert-post"))) + + (component $c + (import "foo" (func $foo)) + (import "assert-post" (func $assert_post)) + (core func $foo (canon lower (func $foo))) + (core func $assert_post (canon lower (func $assert_post))) + + (core module $something + (import "" "foo" (func $foo)) + (import "" "assert-post" (func $assert_post)) + + (func $start + call $foo + call $assert_post + ) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + (export "assert-post" (func $assert_post)) + )) + )) + ) + (instance (instantiate $c + (with "foo" (func $foo)) + (with "assert-post" (func $assert_post)) + )) +) + +;; post-return passes the results +(component + (core module $m + (func (export "foo") (result i32) i32.const 100) + (func (export "foo-post") (param i32) + (if (i32.ne (local.get 0) (i32.const 100)) (then (unreachable)))) + ) + (core instance $m (instantiate $m)) + (func $foo (result u32) + (canon lift (core func $m "foo") (post-return (func $m "foo-post")))) + + (component $c + (import "foo" (func $foo (result u32))) + (core func $foo (canon lower (func $foo))) + + (core module $something + (import "" "foo" (func $foo (result i32))) + (func $start + (if (i32.ne (call $foo) (i32.const 100)) (then (unreachable)))) + (start $start) + ) + (core instance (instantiate $something + (with "" (instance + (export "foo" (func $foo)) + )) + )) + ) + (instance (instantiate $c + (with "foo" (func $foo)) + )) +) + +;; callee retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unreachable") + +;; caller retptr misaligned +(assert_trap + (component + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (result i32) i32.const 0) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result (tuple u32 u32)) + (canon lift (core func $m "r") (memory $m "memory")) + ) + ) + (component $c2 + (import "r" (func $r (result (tuple u32 u32)))) + (core module $libc (memory (export "memory") 1)) + (core instance $libc (instantiate $libc)) + (core func $r (canon lower (func $r) (memory $libc "memory"))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unreachable") + +;; callee argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 4 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unreachable") + +;; caller argptr misaligned +(assert_trap + (component + (type $big (tuple u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32 u32)) + + (component $c1 + (core module $m + (memory (export "memory") 1) + (func (export "r") (param i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + i32.const 4) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $big) + (canon lift (core func $m "r") (memory $m "memory") (realloc (func $m "realloc"))) + ) + ) + (component $c2 + (import "r" (func $r (param "a" $big))) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + ) + (core instance $libc (instantiate $libc)) + (core func $r + (canon lower (func $r) + (memory $libc "memory") + (realloc (func $libc "realloc")) ;; FIXME(wasm-tools#693) should not be necessary + ) + ) + + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "r" (func $c1 "r")))) + ) + "unreachable") + +;; simple variant translation +(component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (type $b' (variant (case "y"))) + (export $b "b" (type $b')) + + (core module $m + (func (export "r") (param i32) (result i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + i32.const 0 + ) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (result $b) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (type $b' (variant (case "y"))) + (import "b" (type $b (eq $b'))) + + (import "r" (func $r (param "a" $a) (result $b))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32) (result i32))) + (func $start + i32.const 0 + call $r + i32.const 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "b" (type $c1 "b")) + (with "r" (func $c1 "r")) + )) +) + +;; invalid variant discriminant in a parameter +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (param i32)) + ) + (core instance $m (instantiate $m)) + (func (export "r") (param "a" $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (param "a" $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (param i32))) + (func $start + i32.const 1 + call $r + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "unreachable") + +;; invalid variant discriminant in a result +(assert_trap + (component + (component $c1 + (type $a' (variant (case "x"))) + (export $a "a" (type $a')) + (core module $m + (func (export "r") (result i32) i32.const 1) + ) + (core instance $m (instantiate $m)) + (func (export "r") (result $a) (canon lift (core func $m "r"))) + ) + (component $c2 + (type $a' (variant (case "x"))) + (import "a" (type $a (eq $a'))) + (import "r" (func $r (result $a))) + (core func $r (canon lower (func $r))) + + (core module $m + (import "" "r" (func $r (result i32))) + (func $start call $r drop) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance (export "r" (func $r)))) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 + (with "a" (type $c1 "a")) + (with "r" (func $c1 "r")) + )) + ) + "unreachable") + + +;; extra bits are chopped off +(component + (component $c1 + (core module $m + (func (export "u") (param i32) + (if (i32.ne (local.get 0) (i32.const 0)) (then (unreachable))) + ) + (func (export "s") (param i32) + (if (i32.ne (local.get 0) (i32.const -1)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "u8") (param "a" u8) (canon lift (core func $m "u"))) + (func (export "u16") (param "a" u16) (canon lift (core func $m "u"))) + (func (export "s8") (param "a" s8) (canon lift (core func $m "s"))) + (func (export "s16") (param "a" s16) (canon lift (core func $m "s"))) + ) + (component $c2 + (import "a" (instance $i + (export "u8" (func (param "a" u8))) + (export "s8" (func (param "a" s8))) + (export "u16" (func (param "a" u16))) + (export "s16" (func (param "a" s16))) + )) + + (core func $u8 (canon lower (func $i "u8"))) + (core func $s8 (canon lower (func $i "s8"))) + (core func $u16 (canon lower (func $i "u16"))) + (core func $s16 (canon lower (func $i "s16"))) + + (core module $m + (import "" "u8" (func $u8 (param i32))) + (import "" "s8" (func $s8 (param i32))) + (import "" "u16" (func $u16 (param i32))) + (import "" "s16" (func $s16 (param i32))) + + (func $start + (call $u8 (i32.const 0)) + (call $u8 (i32.const 0xff00)) + (call $s8 (i32.const -1)) + (call $s8 (i32.const 0xff)) + (call $s8 (i32.const 0xffff)) + + (call $u16 (i32.const 0)) + (call $u16 (i32.const 0xff0000)) + (call $s16 (i32.const -1)) + (call $s16 (i32.const 0xffff)) + (call $s16 (i32.const 0xffffff)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "u8" (func $u8)) + (export "s8" (func $s8)) + (export "u16" (func $u16)) + (export "s16" (func $s16)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; translation of locals between different types +(component + (component $c1 + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export $a "t-a" (type $a')) + (export $b "t-b" (type $b')) + (export $c "t-c" (type $c')) + (export $d "t-d" (type $d')) + (export $e "t-e" (type $e')) + + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (core module $m + (func (export "a") (param i32 i32 i32) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i32.ne (local.get 2) (i32.const 2)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (local.get 2)) (f32.const 3)) (then (unreachable))) + end + ) + (func (export "b") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 4)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 5)) (then (unreachable))) + end + ) + (func (export "c") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 6)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 7)) (then (unreachable))) + end + ) + (func (export "d") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 8)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f64.ne (f64.reinterpret_i64 (local.get 2)) (f64.const 9)) (then (unreachable))) + end + ) + (func (export "e") (param i32 i32 i64) + (i32.eqz (local.get 0)) + if + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (f32.reinterpret_i32 (i32.wrap_i64 (local.get 2))) (f32.const 10)) (then (unreachable))) + else + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 2) (i64.const 11)) (then (unreachable))) + end + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (type $func_a) (canon lift (core func $m "a"))) + (func (export "b") (type $func_b) (canon lift (core func $m "b"))) + (func (export "c") (type $func_c) (canon lift (core func $m "c"))) + (func (export "d") (type $func_d) (canon lift (core func $m "d"))) + (func (export "e") (type $func_e) (canon lift (core func $m "e"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant (case "a" u8) (case "b" float32))) + (type $b' (variant (case "a" u16) (case "b" s64))) + (type $c' (variant (case "a" u64) (case "b" float64))) + (type $d' (variant (case "a" float32) (case "b" float64))) + (type $e' (variant (case "a" float32) (case "b" s64))) + (export "t-a" (type $a (eq $a'))) + (export "t-b" (type $b (eq $b'))) + (export "t-c" (type $c (eq $c'))) + (export "t-d" (type $d (eq $d'))) + (export "t-e" (type $e (eq $e'))) + (type $func_a (func (param "x" bool) (param "a" $a))) + (type $func_b (func (param "x" bool) (param "b" $b))) + (type $func_c (func (param "x" bool) (param "c" $c))) + (type $func_d (func (param "x" bool) (param "d" $d))) + (type $func_e (func (param "x" bool) (param "e" $d))) + + (export "a" (func (type $func_a))) + (export "b" (func (type $func_b))) + (export "c" (func (type $func_c))) + (export "d" (func (type $func_d))) + (export "e" (func (type $func_e))) + )) + + (core func $a (canon lower (func $i "a"))) + (core func $b (canon lower (func $i "b"))) + (core func $c (canon lower (func $i "c"))) + (core func $d (canon lower (func $i "d"))) + (core func $e (canon lower (func $i "e"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 i32))) + (import "" "b" (func $b (param i32 i32 i64))) + (import "" "c" (func $c (param i32 i32 i64))) + (import "" "d" (func $d (param i32 i32 i64))) + (import "" "e" (func $e (param i32 i32 i64))) + + (func $start + ;; upper bits should get masked + (call $a (i32.const 0) (i32.const 0) (i32.const 0xff_02)) + (call $a (i32.const 1) (i32.const 1) (i32.reinterpret_f32 (f32.const 3))) + + ;; upper bits should get masked + (call $b (i32.const 0) (i32.const 0) (i64.const 0xff_00_04)) + (call $b (i32.const 1) (i32.const 1) (i64.const 5)) + + (call $c (i32.const 0) (i32.const 0) (i64.const 6)) + (call $c (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 7))) + + (call $d (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 8)))) + (call $d (i32.const 1) (i32.const 1) (i64.reinterpret_f64 (f64.const 9))) + + (call $e (i32.const 0) (i32.const 0) (i64.extend_i32_u (i32.reinterpret_f32 (f32.const 10)))) + (call $e (i32.const 1) (i32.const 1) (i64.const 11)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + (export "b" (func $b)) + (export "c" (func $c)) + (export "d" (func $d)) + (export "e" (func $e)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; different size variants +(component + (component $c1 + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export $a "t-a" (type $a')) + + (core module $m + (func (export "a") (param i32 i32 f32 i64 i32) + (if (i32.eq (local.get 0) (i32.const 0)) + (then (block + (if (i32.ne (local.get 1) (i32.const 0)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 0)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 1)) + (then (block + (if (i32.ne (local.get 1) (i32.const 1)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 1)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 0)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 2)) + (then (block + (if (i32.ne (local.get 1) (i32.const 2)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 2)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 2)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 0)) (then (unreachable))) + )) + ) + (if (i32.eq (local.get 0) (i32.const 3)) + (then (block + (if (i32.ne (local.get 1) (i32.const 3)) (then (unreachable))) + (if (f32.ne (local.get 2) (f32.const 3)) (then (unreachable))) + (if (i64.ne (local.get 3) (i64.const 3)) (then (unreachable))) + (if (i32.ne (local.get 4) (i32.const 3)) (then (unreachable))) + )) + ) + (if (i32.gt_u (local.get 0) (i32.const 3)) + (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "x" u8) (param "a" $a) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (type $a' (variant + (case "a") + (case "b" float32) + (case "c" (tuple float32 u32)) + (case "d" (tuple float32 u64 u8)) + )) + (export "t-a" (type $a (eq $a'))) + (export "a" (func (param "x" u8) (param "a" $a))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32 i32 f32 i64 i32))) + + (func $start + ;; variant a + (call $a + (i32.const 0) + (i32.const 0) + (f32.const 0) + (i64.const 0) + (i32.const 0)) + ;; variant b + (call $a + (i32.const 1) + (i32.const 1) + (f32.const 1) + (i64.const 0) + (i32.const 0)) + ;; variant c + (call $a + (i32.const 2) + (i32.const 2) + (f32.const 2) + (i64.const 2) + (i32.const 0)) + ;; variant d + (call $a + (i32.const 3) + (i32.const 3) + (f32.const 3) + (i64.const 3) + (i32.const 3)) + ) + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) +) + +;; roundtrip some valid chars +(component + (component $c1 + (core module $m + (func (export "a") (param i32) (result i32) local.get 0) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (result char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i + (export "a" (func (param "a" char) (result char))) + )) + + (core func $a (canon lower (func $i "a"))) + + (core module $m + (import "" "a" (func $a (param i32) (result i32))) + + (func $start + (call $roundtrip (i32.const 0)) + (call $roundtrip (i32.const 0xab)) + (call $roundtrip (i32.const 0xd7ff)) + (call $roundtrip (i32.const 0xe000)) + (call $roundtrip (i32.const 0x10ffff)) + ) + (func $roundtrip (export "roundtrip") (param i32) + local.get 0 + call $a + local.get 0 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "a" (func $a)) + )) + )) + + (func (export "roundtrip") (param "a" char) (canon lift (core func $m "roundtrip"))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + + (export "roundtrip" (func $c2 "roundtrip")) +) + +(assert_return (invoke "roundtrip" (char.const "x"))) +(assert_return (invoke "roundtrip" (char.const "⛳"))) +(assert_return (invoke "roundtrip" (char.const "🍰"))) + +;; invalid chars +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xd800))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "unreachable") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0xdfff))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "unreachable") +(assert_trap + (component + (component $c1 + (core module $m (func (export "a") (param i32))) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" char) (canon lift (core func $m "a"))) + ) + (component $c2 + (import "a" (instance $i (export "a" (func (param "a" char))))) + (core func $a (canon lower (func $i "a"))) + (core module $m + (import "" "a" (func $a (param i32))) + (func $start (call $a (i32.const 0x110000))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "a" (func $a)))))) + ) + (instance $c1 (instantiate $c1)) + (instance $c2 (instantiate $c2 (with "a" (instance $c1)))) + ) + "unreachable") + +;; test that flags get their upper bits all masked off +(component + (type $f1' (flags "f1")) + (type $f8' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8")) + (type $f9' (flags "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" "f9")) + (type $f16' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + )) + (type $f17' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "g9" + )) + (type $f32' (flags + "f1" "f2" "f3" "f4" "f5" "f6" "f7" "f8" + "g1" "g2" "g3" "g4" "g5" "g6" "g7" "g8" + "h1" "h2" "h3" "h4" "h5" "h6" "h7" "h8" + "i1" "i2" "i3" "i4" "i5" "i6" "i7" "i8" + )) + + (component $c1 + (export $f1 "t-f1" (type $f1')) + (export $f8 "t-f8" (type $f8')) + (export $f9 "t-f9" (type $f9')) + (export $f16 "t-f16" (type $f16')) + (export $f17 "t-f17" (type $f17')) + (export $f32 "t-f32" (type $f32')) + (core module $m + (func (export "f1") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1)) (then (unreachable))) + ) + (func (export "f8") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11)) (then (unreachable))) + ) + (func (export "f9") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x111)) (then (unreachable))) + ) + (func (export "f16") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x1111)) (then (unreachable))) + ) + (func (export "f17") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111)) (then (unreachable))) + ) + (func (export "f32") (param i32) + (if (i32.ne (local.get 0) (i32.const 0x11111111)) (then (unreachable))) + ) + ) + (core instance $m (instantiate $m)) + (func (export "f1") (param "a" $f1) (canon lift (core func $m "f1"))) + (func (export "f8") (param "a" $f8) (canon lift (core func $m "f8"))) + (func (export "f9") (param "a" $f9) (canon lift (core func $m "f9"))) + (func (export "f16") (param "a" $f16) (canon lift (core func $m "f16"))) + (func (export "f17") (param "a" $f17) (canon lift (core func $m "f17"))) + (func (export "f32") (param "a" $f32) (canon lift (core func $m "f32"))) + ) + (instance $c1 (instantiate $c1)) + + (component $c2 + (import "a" (instance $i + (export "t-f1" (type $f1 (eq $f1'))) + (export "t-f8" (type $f8 (eq $f8'))) + (export "t-f9" (type $f9 (eq $f9'))) + (export "t-f16" (type $f16 (eq $f16'))) + (export "t-f17" (type $f17 (eq $f17'))) + (export "t-f32" (type $f32 (eq $f32'))) + (export "f1" (func (param "a" $f1))) + (export "f8" (func (param "a" $f8))) + (export "f9" (func (param "a" $f9))) + (export "f16" (func (param "a" $f16))) + (export "f17" (func (param "a" $f17))) + (export "f32" (func (param "a" $f32))) + )) + (core func $f1 (canon lower (func $i "f1"))) + (core func $f8 (canon lower (func $i "f8"))) + (core func $f9 (canon lower (func $i "f9"))) + (core func $f16 (canon lower (func $i "f16"))) + (core func $f17 (canon lower (func $i "f17"))) + (core func $f32 (canon lower (func $i "f32"))) + + (core module $m + (import "" "f1" (func $f1 (param i32))) + (import "" "f8" (func $f8 (param i32))) + (import "" "f9" (func $f9 (param i32))) + (import "" "f16" (func $f16 (param i32))) + (import "" "f17" (func $f17 (param i32))) + (import "" "f32" (func $f32 (param i32))) + + (func $start + (call $f1 (i32.const 0xffffff01)) + (call $f8 (i32.const 0xffffff11)) + (call $f9 (i32.const 0xffffff11)) + (call $f16 (i32.const 0xffff1111)) + (call $f17 (i32.const 0xffff1111)) + (call $f32 (i32.const 0x11111111)) + ) + + (start $start) + ) + (core instance $m (instantiate $m + (with "" (instance + (export "f1" (func $f1)) + (export "f8" (func $f8)) + (export "f9" (func $f9)) + (export "f16" (func $f16)) + (export "f17" (func $f17)) + (export "f32" (func $f32)) + )) + )) + ) + (instance (instantiate $c2 (with "a" (instance $c1)))) +) + +;; Adapters are used slightly out-of-order here to stress the internals of +;; dependencies between adapters. +(component + (core module $m + (func (export "execute")) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) unreachable) + (memory (export "memory") 1) + ) + + (component $root + (core instance $m (instantiate $m)) + (func (export "execute") + (canon lift (core func $m "execute")) + ) + ) + (component $c + (import "backend" (instance $i + (export "execute" (func)) + )) + (core module $shim2 (import "" "0" (func))) + (core instance $m (instantiate $m)) + + ;; This adapter, when fused with itself on the second instantiation of this + ;; component, will depended on the prior instance `$m` so it which means + ;; that the adapter module containing this must be placed in the right + ;; location. + (core func $execute + (canon lower (func $i "execute") (memory $m "memory") (realloc (func $m "realloc"))) + ) + (core instance (instantiate $shim2 + (with "" (instance + (export "0" (func $execute)) + )) + )) + (func (export "execute") (canon lift (core func $m "execute"))) + ) + (instance $root (instantiate $root)) + (instance $c1 (instantiate $c (with "backend" (instance $root)))) + (instance $c2 (instantiate $c (with "backend" (instance $c1)))) +) diff --git a/test/wasmtime/import.wast b/test/wasmtime/import.wast new file mode 100644 index 00000000..20688efe --- /dev/null +++ b/test/wasmtime/import.wast @@ -0,0 +1,20 @@ +(assert_invalid + (component + (import "host-return-two" (func $f (result u32))) + (export "x" (func $f))) + "component export `x` is a reexport of an imported function which is not implemented") + +(assert_unlinkable + (component + (import "host-return-two" (instance)) + ) + "expected instance found func") + +;; empty instances don't need to be supplied by the host, even recursively +;; empty instances. +(component + (import "not-provided-by-the-host" (instance)) + (import "not-provided-by-the-host2" (instance + (export "x" (instance)) + )) +) diff --git a/test/wasmtime/instance.wast b/test/wasmtime/instance.wast new file mode 100644 index 00000000..4216cdc5 --- /dev/null +++ b/test/wasmtime/instance.wast @@ -0,0 +1,327 @@ +(component + (core module $m) + (core instance (instantiate $m)) +) + +(component + (core module $m + (func (export "")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "")) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) +) + +(component + (core module $m + (func (export "a")) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (func (import "" "b")) + ) + (core instance (instantiate $m2 + (with "" (instance (export "b" (func $i "a")))) + )) +) + +;; all kinds of imports for core wasm modules, and register a start function on +;; one module to ensure that everything is correct +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + + (func $start + global.get $g + i32.const 1 + i32.ne + if + unreachable + end + + call $f + ) + + (start $start) + + (data (i32.const 0) "hello") + (elem (i32.const 0) $start) + ) + (core instance (instantiate $m2 + (with "" (instance $i)) + )) +) + +;; Test to see if a component with a type export can be instantiated. +(component + (type string) + (export "a" (type 0)) +) + +;; double-check the start function runs by ensuring that a trap shows up and it +;; sees the wrong value for the global import +(assert_trap + (component + (core module $m + (global (export "g") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 0 + i32.ne + if + unreachable + end + ) + + (start $start) + ) + (core instance (instantiate $m2 (with "" (instance $i)))) + ) + "unreachable") + +;; shuffle around imports to get to what the target core wasm module needs +(component + (core module $m + (func (export "1")) + (table (export "2") 1 funcref) + (memory (export "3") 1) + (global (export "4") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + + (core module $m2 + (import "" "a" (func $f)) + (import "" "b" (table 1 funcref)) + (import "" "c" (memory 1)) + (import "" "d" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "a" (func $i "1")) + (export "b" (table $i "2")) + (export "c" (memory $i "3")) + (export "d" (global $i "4")) + )) + )) +) + +;; indirect references through a synthetic instance +(component + (core module $m + (func (export "a")) + (table (export "b") 1 funcref) + (memory (export "c") 1) + (global (export "d") i32 i32.const 1) + ) + (core instance $i (instantiate $m)) + (core instance $i2 + (export "a1" (func $i "a")) + (export "a2" (table $i "b")) + (export "a3" (memory $i "c")) + (export "a4" (global $i "d")) + ) + + (core module $m2 + (import "" "1" (func $f)) + (import "" "2" (table 1 funcref)) + (import "" "3" (memory 1)) + (import "" "4" (global $g i32)) + ) + (core instance (instantiate $m2 + (with "" (instance + (export "1" (func $i2 "a1")) + (export "2" (table $i2 "a2")) + (export "3" (memory $i2 "a3")) + (export "4" (global $i2 "a4")) + )) + )) +) + +(component + (import "host" (instance $i (export "return-three" (func (result u32))))) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 3 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "return-three")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (type $x' (record (field "x" u32))) + (export "x" (type $x (eq $x'))) + (type $rec' (record (field "x" $x) (field "y" string))) + (export "rec" (type $rec (eq $rec'))) + (export "some-record" (type (eq $rec))))) +) + +(component + (import "host" (instance $i + (export "nested" (instance + (export "return-four" (func (result u32))) + )) + )) + + (core module $m + (import "host" "return-three" (func $three (result i32))) + (func $start + call $three + i32.const 4 + i32.ne + if unreachable end + ) + (start $start) + ) + (core func $three_lower + (canon lower (func $i "nested" "return-four")) + ) + (core instance (instantiate $m + (with "host" (instance (export "return-three" (func $three_lower)))) + )) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module)) + )) + + (core instance (instantiate (module $i "simple-module"))) +) + +(component + (import "host" (instance $i + (export "simple-module" (core module + (export "f" (func (result i32))) + (export "g" (global i32)) + )) + )) + + (core instance $i (instantiate (module $i "simple-module"))) + (core module $verify + (import "host" "f" (func $f (result i32))) + (import "host" "g" (global $g i32)) + + (func $start + call $f + i32.const 101 + i32.ne + if unreachable end + + global.get $g + i32.const 100 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core instance (instantiate $verify (with "host" (instance $i)))) +) + +;; export an instance +(component + (core module $m) + (instance $i (export "m" (core module $m))) + (export "i" (instance $i)) +) +(component + (component $c) + (instance $i (instantiate $c)) + (export "i" (instance $i)) +) +(component + (import "host" (instance $i)) + (export "i" (instance $i)) +) + + +(component definition $C1 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) +(component definition $C2 + (type $r1 (resource (rep i32))) + (export "r" (type $r1)) +) + +(component instance $I1 $C1) +(component instance $I2 $C1) +(component instance $I3 $C2) +(component instance $I4 $C2) + +;; all instances have different resource types +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I2" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I1" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I3" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I2" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") +(assert_unlinkable + (component + (import "I3" (instance $i1 (export "r" (type (sub resource))))) + (alias export $i1 "r" (type $r)) + (import "I4" (instance $i2 (export "r" (type (eq $r))))) + ) + "mismatched resource types") diff --git a/test/wasmtime/linking.wast b/test/wasmtime/linking.wast new file mode 100644 index 00000000..966926f0 --- /dev/null +++ b/test/wasmtime/linking.wast @@ -0,0 +1,18 @@ +(assert_unlinkable + (component + (import "undefined-name" (core module)) + ) + "was not found") +(component $i) +(component + (import "i" (instance)) +) +(assert_unlinkable + (component (import "i" (core module))) + "expected module found instance") +(assert_unlinkable + (component (import "i" (func))) + "expected function found instance") +(assert_unlinkable + (component (import "i" (instance (export "x" (func))))) + "was not found") diff --git a/test/wasmtime/modules.wast b/test/wasmtime/modules.wast new file mode 100644 index 00000000..6014f94e --- /dev/null +++ b/test/wasmtime/modules.wast @@ -0,0 +1,479 @@ +;;! reference_types = true + +(component $foo + (core module (export "a-module")) +) + +;; the above instance can be imported into this component +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +;; specifying extra imports is ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "foo" "bar" (func)) + )) + )) +) + +;; specifying extra exports is not ok +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "the-export" (func)) + )) + )) + ) + "module export `the-export` not defined") + +(component $foo + (core module (export "a-module") + (import "env" "something" (func)) + ) +) + +;; imports must be specified +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module)) + )) + ) + "module import `env::something` not defined") + +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + )) + )) +) + +;; extra imports still ok +(component + (import "foo" (instance + (export "a-module" (core module + (import "env" "something" (func)) + (import "env" "other" (global i32)) + )) + )) +) + +(component $foo + (core module (export "a-module") + (func (export "f")) + ) +) + +;; dropping exports is ok +(component + (import "foo" (instance + (export "a-module" (core module)) + )) +) + +(component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func)) + )) + )) +) + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (func (param i32))) + )) + )) + ) + "expected type `(func (param i32))`, found type `(func)`") + +(assert_unlinkable + (component + (import "foo" (instance + (export "a-module" (core module + (export "f" (global i32)) + )) + )) + ) + "expected global found func") + +(component $foo + (core module (export "m") + (func (export "f")) + (table (export "t") 1 funcref) + (memory (export "m") 1) + (global (export "g") i32 i32.const 0) + ) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (global i32)))) + )) + ) + "expected global found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (func)))) + )) + ) + "expected func found table") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (func)))) + )) + ) + "expected func found memory") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (func)))) + )) + ) + "expected func found global") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "f" (func (param i32))))) + )) + ) + "export `f` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 1 externref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "t" (table 2 funcref)))) + )) + ) + "export `t` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "m" (memory 2)))) + )) + ) + "export `m` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global f32)))) + )) + ) + "export `g` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (export "g" (global (mut i32))))) + )) + ) + "export `g` has the wrong type") + +;; subtyping ok +(component + (import "foo" (instance + (export "m" (core module + (export "t" (table 0 funcref)) + (export "m" (memory 0)) + )) + )) +) + +(component $foo + (core module (export "f") (func (import "" ""))) + (core module (export "t") (table (import "" "") 1 funcref)) + (core module (export "m") (memory (import "" "") 1)) + (core module (export "g") (global (import "" "") i32)) +) + +;; wrong class of item +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (global i32)))) + )) + ) + "expected func found global") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (func)))) + )) + ) + "expected table found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (func)))) + )) + ) + "expected memory found func") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (func)))) + )) + ) + "expected global found func") + +;; wrong item type +(assert_unlinkable + (component + (import "foo" (instance + (export "f" (core module (import "" "" (func (param i32))))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 1 externref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "t" (core module (import "" "" (table 0 funcref)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "m" (core module (import "" "" (memory 0)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global f32)))) + )) + ) + "module import `::` has the wrong type") +(assert_unlinkable + (component + (import "foo" (instance + (export "g" (core module (import "" "" (global (mut i32))))) + )) + ) + "module import `::` has the wrong type") + +;; subtyping ok, but in the opposite direction of imports +(component + (import "foo" (instance + (export "t" (core module (import "" "" (table 2 funcref)))) + (export "m" (core module (import "" "" (memory 2)))) + )) +) + +;; An instance can reexport a module, define a module, and everything can be +;; used by something else +(component $src + (core module (export "m") + (global (export "g") i32 i32.const 2) + ) +) + +(component $reexport + (core module $m1 + (global (export "g") i32 i32.const 1) + ) + (import "src" (instance $src + (export "m" (core module (export "g" (global i32)))) + )) + + (core module $m3 + (global (export "g") i32 i32.const 3) + ) + + (export "m1" (core module $m1)) + (export "m2" (core module $src "m")) + (export "m3" (core module $m3)) +) + +(component + (core type $modulety (module (export "g" (global i32)))) + (import "reexport" (instance $reexport + (export "m1" (core module (type $modulety))) + (export "m2" (core module (type $modulety))) + (export "m3" (core module (type $modulety))) + )) + + (core module $assert_ok + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + (import "m3" "g" (global $m3 i32)) + + (func $assert_ok + block + global.get $m1 + i32.const 1 + i32.eq + br_if 0 + unreachable + end + block + global.get $m2 + i32.const 2 + i32.eq + br_if 0 + unreachable + end + block + global.get $m3 + i32.const 3 + i32.eq + br_if 0 + unreachable + end + ) + + (start $assert_ok) + ) + + (core instance $m1 (instantiate (module $reexport "m1"))) + (core instance $m2 (instantiate (module $reexport "m2"))) + (core instance $m3 (instantiate (module $reexport "m3"))) + + (core instance (instantiate $assert_ok + (with "m1" (instance $m1)) + (with "m2" (instance $m2)) + (with "m3" (instance $m3)) + )) +) + +;; order of imports and exports can be shuffled between definition site and +;; use-site +(component $provider + (core module (export "m") + (import "" "1" (global $i1 i32)) + (import "" "2" (global $i2 i32)) + (import "" "3" (global $i3 i32)) + (import "" "4" (global $i4 i32)) + + (global $g1 i32 i32.const 100) + (global $g2 i32 i32.const 101) + (global $g3 i32 i32.const 102) + (global $g4 i32 i32.const 103) + + (func $assert_imports + (block + global.get $i1 + i32.const 1 + i32.eq + br_if 0 + unreachable) + (block + global.get $i2 + i32.const 2 + i32.eq + br_if 0 + unreachable) + (block + global.get $i3 + i32.const 3 + i32.eq + br_if 0 + unreachable) + (block + global.get $i4 + i32.const 4 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + + (export "g1" (global $g1)) + (export "g2" (global $g2)) + (export "g3" (global $g3)) + (export "g4" (global $g4)) + ) +) + +(component + (import "provider" (instance $provider + (export "m" (core module + (import "" "4" (global i32)) + (import "" "3" (global i32)) + (import "" "2" (global i32)) + (import "" "1" (global i32)) + + (export "g4" (global i32)) + (export "g3" (global i32)) + (export "g2" (global i32)) + (export "g1" (global i32)) + )) + )) + + (core module $imports + (global (export "1") i32 (i32.const 1)) + (global (export "3") i32 (i32.const 3)) + (global (export "2") i32 (i32.const 2)) + (global (export "4") i32 (i32.const 4)) + ) + (core instance $imports (instantiate $imports)) + (core instance $m (instantiate (module $provider "m") + (with "" (instance $imports)) + )) + + (core module $import_globals + (import "" "g4" (global $g4 i32)) + (import "" "g3" (global $g3 i32)) + (import "" "g2" (global $g2 i32)) + (import "" "g1" (global $g1 i32)) + + (func $assert_imports + (block + global.get $g1 + i32.const 100 + i32.eq + br_if 0 + unreachable) + (block + global.get $g2 + i32.const 101 + i32.eq + br_if 0 + unreachable) + (block + global.get $g3 + i32.const 102 + i32.eq + br_if 0 + unreachable) + (block + global.get $g4 + i32.const 103 + i32.eq + br_if 0 + unreachable) + ) + + (start $assert_imports) + ) + + (core instance (instantiate $import_globals (with "" (instance $m)))) +) diff --git a/test/wasmtime/nested.wast b/test/wasmtime/nested.wast new file mode 100644 index 00000000..8cb4c381 --- /dev/null +++ b/test/wasmtime/nested.wast @@ -0,0 +1,451 @@ +;; simple nested component +(component + (component) +) + +;; simple nested component with a nested module +(component + (component + (core module) + ) +) + +;; simple instantiation of a nested component +(component + (component $c) + (instance (instantiate $c)) + (instance (instantiate $c + (with "x" (component $c)) + )) +) + +;; instantiate a module during a nested component, and also instantiate it +;; as an export of the nested component +(component + (component $c + (core module $m) + (core instance (instantiate $m)) + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core instance $i (instantiate (module $i "m"))) +) + +;; instantiate an inner exported module with two different modules and +;; verify imports match +(component + (component $c + (core module $m + (import "" "g" (global $g i32)) + (import "" "f" (func $f (result i32))) + + (func $start + call $f + global.get $g + i32.ne + if unreachable end) + + (start $start) + ) + + (core module $m2 + (global (export "g") i32 i32.const 1) + (func (export "f") (result i32) i32.const 1) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $i2)))) + + (export "m" (core module $m)) + ) + (instance $i (instantiate $c)) + (core module $m2 + (global (export "g") i32 i32.const 5) + (func (export "f") (result i32) i32.const 5) + ) + (core instance $i2 (instantiate $m2)) + (core instance (instantiate (module $i "m") (with "" (instance $i2)))) +) + +;; instantiate an inner component with a module import +(component + (component $c + (import "m" (core module $m + (export "g" (global i32)) + )) + + (core instance $i (instantiate $m)) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $i)))) + ) + + (core module $m + (global (export "g") i32 (i32.const 2)) + ) + (instance (instantiate $c (with "m" (core module $m)))) +) + +;; instantiate an inner component with a module import that itself has imports +(component + (component $c + (import "m" (core module $m + (import "" "g" (global i32)) + )) + (core module $m2 + (global (export "g") i32 i32.const 2100) + ) + (core instance $m2 (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $m2)))) + ) + + (core module $verify + (import "" "g" (global $g i32)) + + (func $start + global.get $g + i32.const 2100 + i32.ne + if unreachable end + ) + + (start $start) + ) + (instance (instantiate $c (with "m" (core module $verify)))) +) + +;; instantiate an inner component with an export from the outer component +(component $c + (core module (export "m") + (import "" "g1" (global $g1 i32)) + (import "" "g2" (global $g2 i32)) + + (func $start + global.get $g1 + i32.const 10000 + i32.ne + if unreachable end + + global.get $g2 + i32.const 20000 + i32.ne + if unreachable end + ) + + (start $start) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + )) + + (component $c + (import "m" (core module $verify + (import "" "g2" (global i32)) + (import "" "g1" (global i32)) + )) + + (core module $m + (global (export "g1") i32 i32.const 10000) + (global (export "g2") i32 i32.const 20000) + ) + (core instance $m (instantiate $m)) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + + (instance (instantiate $c (with "m" (core module $i "m")))) +) + +;; instantiate a reexported module +(component + (core module $m + (global (export "g") i32 i32.const 7) + ) + (component $c + (import "i" (instance $i + (export "m" (core module + (import "" "" (func)) + (export "g" (global i32)) + )) + )) + + (export "m" (core module $i "m")) + ) + + (instance $c (instantiate $c (with "i" (instance (export "m" (core module $m)))))) + (core module $dummy + (func (export "")) + ) + (core instance $dummy (instantiate $dummy)) + + (core instance $m (instantiate (module $c "m") (with "" (instance $dummy)))) + + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 7 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify (with "" (instance $m)))) +) + +;; module must be found through a few layers of imports +(component $c + (core module (export "m") + (global (export "g") i32 i32.const 101) + ) +) + +(component + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (component $c1 + (import "c" (instance $i + (export "m" (core module + (export "g" (global i32)) + )) + )) + (core module $verify + (import "" "g" (global i32)) + (func $start + global.get 0 + i32.const 101 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance $m (instantiate (module $i "m"))) + (core instance (instantiate $verify (with "" (instance $m)))) + ) + (instance (instantiate $c1 (with "c" (instance $i)))) +) + +;; instantiate outer alias to self +(component $C + (core module $m) + (alias outer $C $m (core module $other_m)) + (core instance (instantiate $other_m)) +) + +(component $C + (component $m) + (alias outer $C $m (component $other_m)) + (instance (instantiate $other_m)) +) + + +;; closing over an outer alias which is actually an argument to some +;; instantiation +(component + (component $c + (import "c" (core module $c + (export "a" (global i32)) + )) + + (component (export "c2") + (export "m" (core module $c)) + ) + ) + + (core module $m1 (global (export "a") i32 i32.const 1)) + (core module $m2 (global (export "a") i32 i32.const 2)) + + (instance $c1 (instantiate $c (with "c" (core module $m1)))) + (instance $c2 (instantiate $c (with "c" (core module $m2)))) + + (instance $m1_container (instantiate (component $c1 "c2"))) + (instance $m2_container (instantiate (component $c2 "c2"))) + + (core instance $core1 (instantiate (module $m1_container "m"))) + (core instance $core2 (instantiate (module $m2_container "m"))) + + (core module $verify + (import "core1" "a" (global $a i32)) + (import "core2" "a" (global $b i32)) + + (func $start + global.get $a + i32.const 1 + i32.ne + if unreachable end + + global.get $b + i32.const 2 + i32.ne + if unreachable end + ) + + (start $start) + ) + (core instance (instantiate $verify + (with "core1" (instance $core1)) + (with "core2" (instance $core2)) + )) +) + +;; simple importing of a component +(component + (component $C) + (component $other + (import "x" (component $c)) + (instance (instantiate $c)) + ) + (instance (instantiate $other (with "x" (component $C)))) +) + +;; deep nesting +(component $C + (core module $m + (global (export "g") i32 (i32.const 1)) + ) + (component $c + (core module (export "m") + (global (export "g") i32 (i32.const 2)) + ) + ) + + (component $c1 + (component $c2 (export "a") + (component $c3 (export "a") + (alias outer $C $m (core module $my_module)) + (alias outer $C $c (component $my_component)) + + (export "m" (core module $my_module)) + (export "c" (component $my_component)) + ) + ) + ) + + (instance $i1 (instantiate $c1)) + (instance $i2 (instantiate (component $i1 "a"))) + (instance $i3 (instantiate (component $i2 "a"))) + + (core instance $m1 (instantiate (module $i3 "m"))) + (instance $c (instantiate (component $i3 "c"))) + (core instance $m2 (instantiate (module $c "m"))) + + (core module $verify + (import "m1" "g" (global $m1 i32)) + (import "m2" "g" (global $m2 i32)) + + (func $start + global.get $m1 + i32.const 1 + i32.ne + if unreachable end + + global.get $m2 + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + (core instance (instantiate $verify (with "m1" (instance $m1)) (with "m2" (instance $m2)))) +) + +;; Try threading through component instantiation arguments as various forms of +;; instances. +(component + (component $c + (core module $m (export "m")) + (component $c (export "c") + (core module (export "m")) + ) + (instance $i (instantiate $c)) + (instance $i2 + (export "m" (core module $m)) + (export "c" (component $c)) + (export "i" (instance $i)) + ) + (export "i" (instance $i)) + (export "i2" (instance $i2)) + ) + (instance $i (instantiate $c)) + + (component $another + (import "host" (instance + (export "m" (core module)) + (export "c" (component)) + (export "i" (instance)) + )) + ) + (instance (instantiate $another (with "host" (instance $i)))) + (instance (instantiate $another (with "host" (instance $i "i2")))) + + (instance $reexport + (export "c" (component $i "c")) + (export "m" (core module $i "m")) + (export "i" (instance $i "i")) + ) + (instance (instantiate $another (with "host" (instance $reexport)))) +) + +;; thread host functions around +(component + (import "host-return-two" (func $import (result u32))) + + ;; thread the host function through an instance + (component $c + (import "a" (func $f (result u32))) + (export "f" (func $f)) + ) + (instance $c (instantiate $c (with "a" (func $import)))) + (alias export $c "f" (func $import2)) + + ;; thread the host function into a nested component + (component $c2 + (import "host" (instance $i (export "return-two" (func (result u32))))) + + (core module $m + (import "host" "return-two" (func $host (result i32))) + (func $start + call $host + i32.const 2 + i32.ne + if unreachable end + ) + (start $start) + ) + + (core func $return_two + (canon lower (func $i "return-two")) + ) + (core instance (instantiate $m + (with "host" (instance + (export "return-two" (func $return_two)) + )) + )) + ) + + (instance (instantiate $c2 + (with "host" (instance + (export "return-two" (func $import2)) + )) + )) +) diff --git a/test/wasmtime/resources.wast b/test/wasmtime/resources.wast new file mode 100644 index 00000000..c9f94fec --- /dev/null +++ b/test/wasmtime/resources.wast @@ -0,0 +1,1091 @@ +;; bare bones "intrinsics work" +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r i32) + (local.set $r (call $new (i32.const 100))) + + (if (i32.ne (local.get $r) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r)) (i32.const 100)) (then (unreachable))) + + (call $drop (local.get $r)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +;; cannot call `resource.drop` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "r") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; cannot call `resource.rep` on a nonexistent resource +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "r") + (drop (call $rep (i32.const 0))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + )) + )) + + (func (export "r") (canon lift (core func $i "r"))) +) +(assert_trap (invoke "r") "unknown handle index 0") + +;; index reuse behavior of handles +(component + (type $r (resource (rep i32))) + (core func $rep (canon resource.rep $r)) + (core func $new (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "rep" (func $rep (param i32) (result i32))) + (import "" "new" (func $new (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local $r3 i32) + (local $r4 i32) + + ;; resources assigned sequentially + (local.set $r1 (call $new (i32.const 100))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + (local.set $r2 (call $new (i32.const 200))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (local.set $r3 (call $new (i32.const 300))) + (if (i32.ne (local.get $r3) (i32.const 3)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 200)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; reallocate r2 + (call $drop (local.get $r2)) + (local.set $r2 (call $new (i32.const 400))) + + ;; should have reused index 1 + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 100)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 400)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 300)) (then (unreachable))) + + ;; deallocate, then reallocate + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + + (local.set $r1 (call $new (i32.const 500))) + (local.set $r2 (call $new (i32.const 600))) + (local.set $r3 (call $new (i32.const 700))) + + ;; representations all look good + (if (i32.ne (call $rep (local.get $r1)) (i32.const 500)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r2)) (i32.const 600)) (then (unreachable))) + (if (i32.ne (call $rep (local.get $r3)) (i32.const 700)) (then (unreachable))) + + ;; indices should be lifo + (if (i32.ne (local.get $r1) (i32.const 3)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + (if (i32.ne (local.get $r3) (i32.const 1)) (then (unreachable))) + + ;; bump one more time + (local.set $r4 (call $new (i32.const 800))) + (if (i32.ne (local.get $r4) (i32.const 4)) (then (unreachable))) + + ;; deallocate everything + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + (call $drop (local.get $r3)) + (call $drop (local.get $r4)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "rep" (func $rep)) + (export "new" (func $new)) + (export "drop" (func $drop)) + )) + )) +) + +(assert_unlinkable + (component + (import "host" (instance + (export "missing" (type (sub resource))) + )) + ) + "was not found") +(assert_unlinkable + (component + (import "host" (instance + (export "return-three" (type (sub resource))) + )) + ) + "expected resource found func") + +;; all resources can be uniquely imported +(component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (sub resource))) + )) +) + +;; equality constraints also work +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) +) + +;; equality constraints are checked if resources are supplied +(assert_unlinkable + (component + (import "host" (instance + (export "resource1" (type (sub resource))) + (export "resource2" (type $r1 (sub resource))) + (export "resource1-again" (type (eq $r1))) + )) + ) + "mismatched resource types") + +;; equality constraints mean that types don't need to be supplied +(component + (import "host" (instance + (export "resource1" (type $r1 (sub resource))) + (export "resource2" (type (sub resource))) + (export "this-name-is-not-provided-in-the-wast-harness" (type (eq $r1))) + )) +) + +;; simple properties of handles +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "assert" (func $assert (param i32 i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + ;; assert r1/r2 are sequential + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; reallocate r1 and it should be reassigned the same index + (call $drop (local.get $r1)) + (local.set $r1 (call $ctor (i32.const 300))) + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + + ;; internal values should match + (call $assert (local.get $r1) (i32.const 300)) + (call $assert (local.get $r2) (i32.const 200)) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "assert" (func $assert)) + )) + )) +) + +;; Using an index that has never been valid is a trap +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[static]resource1.assert" (func $assert)) + (core func $assert (canon lower (func $assert))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + + (func (export "f") + (call $assert (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Using an index which was previously valid but no longer valid is also a trap. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.assert" (func (param "r" (own $r)) (param "rep" u32))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.assert" (func $assert)) + + (core func $assert (canon lower (func $assert))) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "assert" (func $assert (param i32 i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $assert (global.get $handle) (i32.const 100)) + ) + + (func (export "f2") + (call $assert (global.get $handle) (i32.const 100)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "assert" (func $assert)) + (export "ctor" (func $ctor)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; Also invalid to pass a previously valid handle to the drop intrinsic +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (global $handle (mut i32) i32.const 0) + + (func (export "f") + (global.set $handle (call $ctor (i32.const 100))) + (call $drop (global.get $handle)) + ) + + (func (export "f2") + (call $drop (global.get $handle)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) + (func (export "f2") (canon lift (core func $i "f2"))) +) + +(assert_return (invoke "f")) +(assert_trap (invoke "f2") "unknown handle index") + +;; If an inner component instantiates a resource then an outer component +;; should not implicitly have access to that resource. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + + ;; an inner component which upon instantiation will invoke the constructor, + ;; assert that it's zero, and then forget about it. + (component $inner + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "[constructor]resource1" (func $ctor)) + + (core func $ctor (canon lower (func $ctor))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 0)) (then (unreachable))) + ) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + ) + (instance $i (instantiate $inner (with "host" (instance $host)))) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 0. The index 0 should be valid within the above component, but + ;; it is not valid within this component + (alias export $host "resource1" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index") + +;; Same as the above test, but for resources defined within a component +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + + (func $start + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (start $start) + ) + (core instance $i (instantiate $m + (with "" (instance (export "ctor" (func $ctor)))) + )) + (export "r" (type $r)) + ) + (instance $i (instantiate $inner)) + + ;; the rest of this component which is a single function that invokes `drop` + ;; for index 1. The index 1 should be valid within the above component, but + ;; it is not valid within this component + (alias export $i "r" (type $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 1") + +;; Each instantiation of a component generates a unique resource type, so +;; allocating in one component and deallocating in another should fail. +(component + (component $inner + (type $r (resource (rep i32))) + + (core func $ctor (canon resource.new $r)) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner)) + (instance $i2 (instantiate $inner)) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Same as above, but the same host resource type is imported into a +;; component that is instantiated twice. Each component instance should +;; receive different tables tracking resources so a resource allocated in one +;; should not be visible in the other. +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + )) + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + + (component $inner + (import "r" (type $r (sub resource))) + (import "[constructor]r" (func $ctor (param "r" u32) (result (own $r)))) + + (core func $ctor (canon lower (func $ctor))) + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "drop" (func $drop (param i32))) + + (func (export "alloc") + (if (i32.ne (call $ctor (i32.const 100)) (i32.const 1)) (then (unreachable))) + ) + (func (export "dealloc") + (call $drop (i32.const 1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "drop" (func $drop)) + )) + )) + (func (export "alloc") (canon lift (core func $i "alloc"))) + (func (export "dealloc") (canon lift (core func $i "dealloc"))) + ) + (instance $i1 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + (instance $i2 (instantiate $inner + (with "r" (type $r)) + (with "[constructor]r" (func $ctor)) + )) + + (alias export $i1 "alloc" (func $alloc_in_1)) + (alias export $i1 "dealloc" (func $dealloc_in_1)) + (alias export $i2 "alloc" (func $alloc_in_2)) + (alias export $i2 "dealloc" (func $dealloc_in_2)) + + (export "alloc-in1" (func $alloc_in_1)) + (export "dealloc-in1" (func $dealloc_in_1)) + (export "alloc-in2" (func $alloc_in_2)) + (export "dealloc-in2" (func $dealloc_in_2)) +) + +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "dealloc-in1")) +(assert_return (invoke "alloc-in1")) +(assert_return (invoke "alloc-in2")) +(assert_return (invoke "dealloc-in2")) +(assert_trap (invoke "dealloc-in2") "unknown handle index") + +;; Multiple copies of intrinsics all work +(component + (type $r (resource (rep i32))) + + (core func $new1 (canon resource.new $r)) + (core func $new2 (canon resource.new $r)) + (core func $drop1 (canon resource.drop $r)) + (core func $drop2 (canon resource.drop $r)) + + (core module $m + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + + (func $start + ;; 2x2 matrix of pairing new/drop + (call $drop1 (call $new1 (i32.const 101))) + (call $drop2 (call $new1 (i32.const 102))) + (call $drop1 (call $new2 (i32.const 103))) + (call $drop2 (call $new2 (i32.const 104))) + + ;; should be referencing the same namespace + (if (i32.ne (call $new1 (i32.const 105)) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $new2 (i32.const 105)) (i32.const 2)) (then (unreachable))) + + ;; use different drops out of order + (call $drop2 (i32.const 1)) + (call $drop1 (i32.const 2)) + ) + + (start $start) + ) + + (core instance (instantiate $m + (with "" (instance + (export "new1" (func $new1)) + (export "new2" (func $new2)) + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + )) + )) +) + +;; u32::MAX isn't special in some weird way, it's just probably always invalid +;; because that's a lot of handles. +(component + (type $r (resource (rep i32))) + + (core func $drop (canon resource.drop $r)) + + (core module $m + (import "" "drop" (func $drop (param i32))) + + (func (export "f") + (call $drop (i32.const 0xffffffff)) + ) + ) + + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) +) +(assert_trap (invoke "f") "unknown handle index") + +;; Test behavior of running a destructor for local resources +(component + (core module $m1 + (global $drops (mut i32) i32.const 0) + (global $last_drop (mut i32) i32.const -1) + + (func (export "dtor") (param i32) + (global.set $drops (i32.add (global.get $drops) (i32.const 1))) + (global.set $last_drop (local.get 0)) + ) + (func (export "drops") (result i32) global.get $drops) + (func (export "last-drop") (result i32) global.get $last_drop) + ) + (core instance $i1 (instantiate $m1)) + + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32) (dtor (func $i1 "dtor")))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + (import "i1" "drops" (func $drops (result i32))) + (import "i1" "last-drop" (func $last-drop (result i32))) + + (func $start + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $new1 (i32.const 100))) + (local.set $r2 (call $new2 (i32.const 200))) + + ;; indexes start at 1 and while they have distinct types they should be + ;; within the same table. + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + ;; nothing should be dropped yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; dropping a resource without a destructor is ok, but shouldn't tamper + ;; with anything. + (call $drop1 (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const -1)) (then (unreachable))) + + ;; drop r2 which should record a drop and additionally record the private + ;; representation value which was dropped + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + + ;; do it all over again + (local.set $r2 (call $new2 (i32.const 300))) + (call $drop2 (local.get $r2)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 300)) (then (unreachable))) + ) + + (start $start) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + (with "i1" (instance $i1)) + )) +) + +;; Test dropping a host resource +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[static]resource1.last-drop" (func (result u32))) + (export "[static]resource1.drops" (func (result u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[static]resource1.last-drop" (func $last-drop)) + (alias export $host "[static]resource1.drops" (func $drops)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $last-drop (canon lower (func $last-drop))) + (core func $drops (canon lower (func $drops))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "last-drop" (func $last-drop (result i32))) + (import "" "drops" (func $raw-drops (result i32))) + + (global $init-drop-cnt (mut i32) i32.const 0) + + (func $drops (result i32) + (i32.sub (call $raw-drops) (global.get $init-drop-cnt)) + ) + + (func $start + (local $r1 i32) + (global.set $init-drop-cnt (call $raw-drops)) + + (local.set $r1 (call $ctor (i32.const 100))) + + ;; should be no drops yet + (if (i32.ne (call $drops) (i32.const 0)) (then (unreachable))) + + ;; should count a drop + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 1)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 100)) (then (unreachable))) + + ;; do it again to be sure + (local.set $r1 (call $ctor (i32.const 200))) + (call $drop (local.get $r1)) + (if (i32.ne (call $drops) (i32.const 2)) (then (unreachable))) + (if (i32.ne (call $last-drop) (i32.const 200)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "last-drop" (func $last-drop)) + (export "drops" (func $drops)) + )) + )) +) + +;; Test some bare-bones basics of borrowed resources +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "rep" u32))) + (export "[method]resource1.take-borrow" (func (param "self" (borrow $r)) (param "b" (borrow $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.simple" (func $simple)) + (alias export $host "[method]resource1.take-borrow" (func $take-borrow)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $simple (canon lower (func $simple))) + (core func $take-own (canon lower (func $take-own))) + (core func $take-borrow (canon lower (func $take-borrow))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "simple" (func $simple (param i32 i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + (import "" "take-borrow" (func $take-borrow (param i32 i32))) + + + (func $start + (local $r1 i32) + (local $r2 i32) + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r1) (i32.const 100)) + (call $simple (local.get $r2) (i32.const 200)) + (call $simple (local.get $r2) (i32.const 200)) + + (call $drop (local.get $r1)) + (call $drop (local.get $r2)) + + + (local.set $r1 (call $ctor (i32.const 200))) + (local.set $r2 (call $ctor (i32.const 300))) + (call $take-borrow (local.get $r1) (local.get $r2)) + (call $take-borrow (local.get $r2) (local.get $r1)) + (call $take-borrow (local.get $r1) (local.get $r1)) + (call $take-borrow (local.get $r2) (local.get $r2)) + + (call $take-own (local.get $r1) (call $ctor (i32.const 400))) + (call $take-own (local.get $r2) (call $ctor (i32.const 500))) + (call $take-own (local.get $r2) (local.get $r1)) + (call $drop (local.get $r2)) + + ;; table should be empty at this point, so a fresh allocation should get + ;; index 0 + (if (i32.ne (call $ctor (i32.const 600)) (i32.const 1)) (then (unreachable))) + ) + + (start $start) + ) + (core instance (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "simple" (func $simple)) + (export "take-own" (func $take-own)) + (export "take-borrow" (func $take-borrow)) + )) + )) +) + +;; Cannot pass out an owned resource when it's borrowed by the same call +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[constructor]resource1" (func (param "r" u32) (result (own $r)))) + (export "[method]resource1.take-own" (func (param "self" (borrow $r)) (param "b" (own $r)))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[constructor]resource1" (func $ctor)) + (alias export $host "[method]resource1.take-own" (func $take-own)) + + (core func $drop (canon resource.drop $r)) + (core func $ctor (canon lower (func $ctor))) + (core func $take-own (canon lower (func $take-own))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "take-own" (func $take-own (param i32 i32))) + + + (func (export "f") + (local $r i32) + (local.set $r (call $ctor (i32.const 100))) + (call $take-own (local.get $r) (local.get $r)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "ctor" (func $ctor)) + (export "take-own" (func $take-own)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "cannot remove owned resource while borrowed") + +;; Borrows must actually exist +(component + (import "host" (instance $host + (export "resource1" (type $r (sub resource))) + (export "[method]resource1.simple" (func (param "self" (borrow $r)) (param "b" u32))) + )) + + (alias export $host "resource1" (type $r)) + (alias export $host "[method]resource1.simple" (func $simple)) + + (core func $drop (canon resource.drop $r)) + (core func $simple (canon lower (func $simple))) + + (core module $m + (import "" "drop" (func $drop (param i32))) + (import "" "simple" (func $simple (param i32 i32))) + + + (func (export "f") + (call $simple (i32.const 0) (i32.const 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "drop" (func $drop)) + (export "simple" (func $simple)) + )) + )) + + (func (export "f") (canon lift (core func $i "f"))) +) + +(assert_trap (invoke "f") "unknown handle index 0") + +(component + (component $A + (type $t' (resource (rep i32))) + (export $t "t" (type $t')) + + (core func $ctor (canon resource.new $t)) + (core func $dtor (canon resource.drop $t)) + (core func $rep (canon resource.rep $t)) + + (core module $m + (import "" "dtor" (func $dtor (param i32))) + (import "" "rep" (func $rep (param i32) (result i32))) + + (func (export "[method]t.assert") (param i32 i32) + (if (i32.ne (local.get 0) (local.get 1)) (then (unreachable))) + ) + (func (export "[static]t.assert-own") (param i32 i32) + (if (i32.ne (call $rep (local.get 0)) (local.get 1)) (then (unreachable))) + (call $dtor (local.get 0)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "dtor" (func $dtor)) + (export "rep" (func $rep)) + )) + )) + (func (export "[constructor]t") (param "x" u32) (result (own $t)) + (canon lift (core func $ctor))) + (func (export "[method]t.assert") (param "self" (borrow $t)) (param "x" u32) + (canon lift (core func $i "[method]t.assert"))) + (func (export "[static]t.assert-own") (param "self" (own $t)) (param "x" u32) + (canon lift (core func $i "[static]t.assert-own"))) + ) + (instance $a (instantiate $A)) + + (component $B + (import "a" (instance $i + (export "t" (type $t (sub resource))) + (export "[constructor]t" (func (param "x" u32) (result (own $t)))) + (export "[method]t.assert" (func (param "self" (borrow $t)) (param "x" u32))) + (export "[static]t.assert-own" (func (param "self" (own $t)) (param "x" u32))) + )) + + (alias export $i "t" (type $t)) + (alias export $i "[constructor]t" (func $ctor)) + (alias export $i "[method]t.assert" (func $assert-borrow)) + (alias export $i "[static]t.assert-own" (func $assert-own)) + + (core func $ctor (canon lower (func $ctor))) + (core func $dtor (canon resource.drop $t)) + (core func $assert-own (canon lower (func $assert-own))) + (core func $assert-borrow (canon lower (func $assert-borrow))) + + (core module $m + (import "" "ctor" (func $ctor (param i32) (result i32))) + (import "" "dtor" (func $dtor (param i32))) + (import "" "assert-own" (func $assert-own (param i32 i32))) + (import "" "assert-borrow" (func $assert-borrow (param i32 i32))) + + (func (export "f") + (local $r1 i32) + (local $r2 i32) + + (local.set $r1 (call $ctor (i32.const 100))) + (local.set $r2 (call $ctor (i32.const 200))) + + (if (i32.ne (local.get $r1) (i32.const 1)) (then (unreachable))) + (if (i32.ne (local.get $r2) (i32.const 2)) (then (unreachable))) + + (call $assert-borrow (local.get $r2) (i32.const 200)) + (call $assert-borrow (local.get $r1) (i32.const 100)) + + (call $assert-own (local.get $r2) (i32.const 200)) + (call $dtor (local.get $r1)) + ) + ) + (core instance $i (instantiate $m + (with "" (instance + (export "ctor" (func $ctor)) + (export "dtor" (func $dtor)) + (export "assert-own" (func $assert-own)) + (export "assert-borrow" (func $assert-borrow)) + )) + )) + (func (export "f") (canon lift (core func $i "f"))) + ) + (instance $b (instantiate $B (with "a" (instance $a)))) + (export "f" (func $b "f")) +) + +(assert_return (invoke "f")) + +;; Test destructor behavior when using the wrong resource type +(component definition $C + (type $r1 (resource (rep i32))) + (type $r2 (resource (rep i32))) + + (core func $drop1 (canon resource.drop $r1)) + (core func $drop2 (canon resource.drop $r2)) + (core func $new1 (canon resource.new $r1)) + (core func $new2 (canon resource.new $r2)) + + (core module $m2 + (import "" "drop1" (func $drop1 (param i32))) + (import "" "drop2" (func $drop2 (param i32))) + (import "" "new1" (func $new1 (param i32) (result i32))) + (import "" "new2" (func $new2 (param i32) (result i32))) + + (func (export "drop-r1-as-r2") (call $drop2 (call $new1 (i32.const 100)))) + (func (export "return-r1-as-r2") (result i32) (call $new1 (i32.const 100))) + ) + + (core instance $i2 (instantiate $m2 + (with "" (instance + (export "drop1" (func $drop1)) + (export "drop2" (func $drop2)) + (export "new1" (func $new1)) + (export "new2" (func $new2)) + )) + )) + + (export $r2' "r2" (type $r2)) + (func (export "drop-r1-as-r2") (canon lift (core func $i2 "drop-r1-as-r2"))) + (func (export "return-r1-as-r2") (result (own $r2')) (canon lift (core func $i2 "return-r1-as-r2"))) +) + +(component instance $C1 $C) +(assert_trap (invoke "drop-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") +(component instance $C1 $C) +(assert_trap (invoke "return-r1-as-r2") "handle index 1 used with the wrong type, expected guest-defined resource but found a different guest-defined resource") diff --git a/test/wasmtime/restrictions.wast b/test/wasmtime/restrictions.wast new file mode 100644 index 00000000..9bd53e7e --- /dev/null +++ b/test/wasmtime/restrictions.wast @@ -0,0 +1,22 @@ +(assert_invalid + (component (import "x" (component))) + "root-level component imports are not supported") + +(assert_invalid + (component (component (export "x"))) + "exporting a component from the root component is not supported") + +(assert_invalid + (component + (import "f" (func $f)) + (export "f" (func $f)) + ) + "component export `f` is a reexport of an imported function which is not implemented") + +(assert_invalid + (component + (import "x" (component + (export "x" (type (sub resource))) + )) + ) + "root-level component imports are not supported") diff --git a/test/wasmtime/simple.wast b/test/wasmtime/simple.wast new file mode 100644 index 00000000..7bf2ab1e --- /dev/null +++ b/test/wasmtime/simple.wast @@ -0,0 +1,42 @@ +(component) + +(component + (core module) +) + +(component + (core module) + (core module) + (core module) +) + +(component + (core module + (func (export "a") (result i32) i32.const 0) + (func (export "b") (result i64) i64.const 0) + ) + (core module + (func (export "c") (result f32) f32.const 0) + (func (export "d") (result f64) f64.const 0) + ) +) + +(assert_invalid + (component + (import "a" (component)) + ) + "root-level component imports are not supported") + +(assert_invalid + (component + (component (export "a")) + ) + "exporting a component from the root component is not supported") + +(component + (core module $m (func (export ""))) + (core instance $m (instantiate $m)) + (func (export "a") (canon lift (core func $m ""))) +) + +(assert_return (invoke "a")) diff --git a/test/wasmtime/strings.wast b/test/wasmtime/strings.wast new file mode 100644 index 00000000..e53caa35 --- /dev/null +++ b/test/wasmtime/strings.wast @@ -0,0 +1,110 @@ +;;! multi_memory = true + +;; unaligned utf16 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unreachable") + +;; unaligned latin1+utf16 string, even with the latin1 encoding +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory")) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=latin1+utf16 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 1) (i32.const 0))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unreachable") + +;; out of bounds utf8->utf8 string +(assert_trap + (component + (component $c + (core module $m + (func (export "") (param i32 i32)) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) i32.const 0) + (memory (export "memory") 1) + ) + (core instance $m (instantiate $m)) + (func (export "a") (param "a" string) + (canon lift (core func $m "") (realloc (func $m "realloc")) (memory $m "memory") + string-encoding=utf8) + ) + ) + + (component $c2 + (import "a" (func $f (param "a" string))) + (core module $libc + (memory (export "memory") 1) + ) + (core instance $libc (instantiate $libc)) + (core func $f (canon lower (func $f) string-encoding=utf8 (memory $libc "memory"))) + (core module $m + (import "" "" (func $f (param i32 i32))) + + (func $start (call $f (i32.const 0x8000_0000) (i32.const 1))) + (start $start) + ) + (core instance (instantiate $m (with "" (instance (export "" (func $f)))))) + ) + + (instance $c (instantiate $c)) + (instance $c2 (instantiate $c2 (with "a" (func $c "a")))) + ) + "unreachable") diff --git a/test/wasmtime/tags.wast b/test/wasmtime/tags.wast new file mode 100644 index 00000000..cac1fdec --- /dev/null +++ b/test/wasmtime/tags.wast @@ -0,0 +1,14 @@ +;;! exceptions = true + +(component + (core module $a (tag (export "t"))) + (core module $b (import "a" "t" (tag))) + + (core instance $a (instantiate $a)) + (core instance (instantiate $b (with "a" (instance $a)))) + (core instance (instantiate $b + (with "a" (instance + (export "t" (tag $a "t")) + )) + )) +) diff --git a/test/wasmtime/types.wast b/test/wasmtime/types.wast new file mode 100644 index 00000000..9596ebe6 --- /dev/null +++ b/test/wasmtime/types.wast @@ -0,0 +1,355 @@ +(component + (type string) + (type (func (param "a" string))) + (type $r (record (field "x" (result)) (field "y" string))) + (type $u (variant (case "r" $r) (case "s" string))) + (type $e (result $u (error u32))) + (type (result $u)) + (type (result (error $u))) + (type (result)) + + (type (func (param "a" $e) (result (option $r)))) + + (type (variant + (case "a" string) + (case "b" u32) + (case "c" float32) + (case "d" float64) + )) + + (type $errno (enum "a" "b" "e")) + (type (list $errno)) + (type $oflags (flags "read" "write" "exclusive")) + (type (tuple $oflags $errno $r)) + + ;; primitives in functions + (type (func + (param "a" bool) + (param "b" u8) + (param "c" s8) + (param "d" u16) + (param "e" s16) + (param "f" u32) + (param "g" s32) + (param "h" u64) + (param "i" s64) + (param "j" char) + (param "k" string) + )) + + ;; primitives in types + (type bool) + (type u8) + (type s8) + (type u16) + (type s16) + (type u32) + (type s32) + (type u64) + (type s64) + (type char) + (type string) +) + +(component + (type $empty (func)) + (type (func (param "a" string) (result u32))) + (type (component)) + (core type (module)) + (core type (func)) + (type (instance)) + + (type (component + (import "x" (func (type $empty))) + (import "y" (func)) + (import "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (type (instance + (export "x" (func (type $empty))) + (export "y" (func)) + (export "z" (component)) + + (type $t (instance)) + + (export "a" (core module)) + (export "b" (instance (type $t))) + )) + + (core type (module + (import "" "" (func (param i32))) + (import "" "1" (func (result i32))) + (export "1" (global i32)) + (export "2" (memory 1)) + (export "3" (table 1 funcref)) + )) +) + +;; outer core aliases work +(component $C + (core type $f (func)) + (core type $m (module)) + + (component $C2 + (alias outer $C $f (core type $my_f)) + (import "a" (core module (type $m))) + (import "x" (core module + (alias outer $C2 $my_f (type $my_f)) + (import "" "1" (func (type $my_f))) + )) + ) +) + +;; type exports work +(component $C + (component $C2 + (type string) + (export "x" (type 0)) + ) + (instance (instantiate 0)) + (alias export 0 "x" (type)) + (export "x" (type 0)) +) + +(component + (core module $m (func (export "") (param i32) (result i32) local.get 0)) + (core instance $m (instantiate $m)) + (func (export "i-to-b") (param "a" u32) (result bool) (canon lift (core func $m ""))) + (func (export "i-to-u8") (param "a" u32) (result u8) (canon lift (core func $m ""))) + (func (export "i-to-s8") (param "a" u32) (result s8) (canon lift (core func $m ""))) + (func (export "i-to-u16") (param "a" u32) (result u16) (canon lift (core func $m ""))) + (func (export "i-to-s16") (param "a" u32) (result s16) (canon lift (core func $m ""))) +) +(assert_return (invoke "i-to-b" (u32.const 0)) (bool.const false)) +(assert_return (invoke "i-to-b" (u32.const 1)) (bool.const true)) +(assert_return (invoke "i-to-b" (u32.const 2)) (bool.const true)) +(assert_return (invoke "i-to-u8" (u32.const 0x00)) (u8.const 0)) +(assert_return (invoke "i-to-u8" (u32.const 0x01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf01)) (u8.const 1)) +(assert_return (invoke "i-to-u8" (u32.const 0xf00)) (u8.const 0)) +(assert_return (invoke "i-to-s8" (u32.const 0xffffffff)) (s8.const -1)) +(assert_return (invoke "i-to-s8" (u32.const 127)) (s8.const 127)) +(assert_return (invoke "i-to-u16" (u32.const 0)) (u16.const 0)) +(assert_return (invoke "i-to-u16" (u32.const 1)) (u16.const 1)) +(assert_return (invoke "i-to-u16" (u32.const 0xffffffff)) (u16.const 0xffff)) +(assert_return (invoke "i-to-s16" (u32.const 0)) (s16.const 0)) +(assert_return (invoke "i-to-s16" (u32.const 1)) (s16.const 1)) +(assert_return (invoke "i-to-s16" (u32.const 0xffffffff)) (s16.const -1)) + +(assert_invalid + (component + (type $t1 string) + (type $t2 (list $t1)) + (type $t3 (list $t2)) + (type $t4 (list $t3)) + (type $t5 (list $t4)) + (type $t6 (list $t5)) + (type $t7 (list $t6)) + (type $t8 (list $t7)) + (type $t9 (list $t8)) + (type $t10 (list $t9)) + (type $t11 (list $t10)) + (type $t12 (list $t11)) + (type $t13 (list $t12)) + (type $t14 (list $t13)) + (type $t15 (list $t14)) + (type $t16 (list $t15)) + (type $t17 (list $t16)) + (type $t18 (list $t17)) + (type $t19 (list $t18)) + (type $t20 (list $t19)) + (type $t21 (list $t20)) + (type $t22 (list $t21)) + (type $t23 (list $t22)) + (type $t24 (list $t23)) + (type $t25 (list $t24)) + (type $t26 (list $t25)) + (type $t27 (list $t26)) + (type $t28 (list $t27)) + (type $t29 (list $t28)) + (type $t30 (list $t29)) + (type $t31 (list $t30)) + (type $t32 (list $t31)) + (type $t33 (list $t32)) + (type $t34 (list $t33)) + (type $t35 (list $t34)) + (type $t36 (list $t35)) + (type $t37 (list $t36)) + (type $t38 (list $t37)) + (type $t39 (list $t38)) + (type $t40 (list $t39)) + (type $t41 (list $t40)) + (type $t42 (list $t41)) + (type $t43 (list $t42)) + (type $t44 (list $t43)) + (type $t45 (list $t44)) + (type $t46 (list $t45)) + (type $t47 (list $t46)) + (type $t48 (list $t47)) + (type $t49 (list $t48)) + (type $t50 (list $t49)) + (type $t51 (list $t50)) + (type $t52 (list $t51)) + (type $t53 (list $t52)) + (type $t54 (list $t53)) + (type $t55 (list $t54)) + (type $t56 (list $t55)) + (type $t57 (list $t56)) + (type $t58 (list $t57)) + (type $t59 (list $t58)) + (type $t60 (list $t59)) + (type $t61 (list $t60)) + (type $t62 (list $t61)) + (type $t63 (list $t62)) + (type $t64 (list $t63)) + (type $t65 (list $t64)) + (type $t66 (list $t65)) + (type $t67 (list $t66)) + (type $t68 (list $t67)) + (type $t69 (list $t68)) + (type $t70 (list $t69)) + (type $t71 (list $t70)) + (type $t72 (list $t71)) + (type $t73 (list $t72)) + (type $t74 (list $t73)) + (type $t75 (list $t74)) + (type $t76 (list $t75)) + (type $t77 (list $t76)) + (type $t78 (list $t77)) + (type $t79 (list $t78)) + (type $t80 (list $t79)) + (type $t81 (list $t80)) + (type $t82 (list $t81)) + (type $t83 (list $t82)) + (type $t84 (list $t83)) + (type $t85 (list $t84)) + (type $t86 (list $t85)) + (type $t87 (list $t86)) + (type $t88 (list $t87)) + (type $t89 (list $t88)) + (type $t90 (list $t89)) + (type $t91 (list $t90)) + (type $t92 (list $t91)) + (type $t93 (list $t92)) + (type $t94 (list $t93)) + (type $t95 (list $t94)) + (type $t96 (list $t95)) + (type $t97 (list $t96)) + (type $t98 (list $t97)) + (type $t99 (list $t98)) + (type $t100 (list $t99)) + (type $t101 (list $t100)) + (export "t" (type $t101)) + ) + "type nesting is too deep") + +(component + (type (instance + (export "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) + + (type (component + (import "x" (instance $x + (type $t u32) + (export "y" (type (eq $t))) + )) + (alias export $x "y" (type $t)) + (export "my-y" (type (eq $t))) + )) +) + +(component + (type $t u32) + (export $t2 "t" (type $t)) + (type $r (record (field "x" $t2))) + (export "r" (type $r)) +) + +(component + (component + (import "x" (instance $i + (type $i u32) + (export "i" (type (eq $i))) + )) + (alias export $i "i" (type $i)) + (export "i" (type $i)) + ) +) + +(component + (type $u u32) + (instance $i + (export "i" (type $u)) + ) + (alias export $i "i" (type $i)) + (export "i" (type $i)) +) + +(component + (component $c + (type $t u32) + (export "t" (type $t)) + ) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) +) + +(component + (component $c + (import "x" (component $c + (type $t u32) + (export "t" (type (eq $t))) + )) + (instance $c (instantiate $c)) + (export "i" (type $c "t")) + ) + + (component $x + (type $t u32) + (export "t" (type $t)) + ) + + (instance $c (instantiate $c (with "x" (component $x)))) +) + +(component + (type $t1 u64) + (import "a" (type $t2 (eq $t1))) + (import "b" (type $t3 (eq $t2))) +) + +(component + (import "a" (instance + (type $t1 u64) + (export "a" (type $t2 (eq $t1))) + (export "b" (type (eq $t2))) + )) +) + +(component + (type (export "x") (component + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +) + +(component + (type (export "x") (instance + (type $t' (instance + (export "r" (type (sub resource))) + )) + (export "t" (instance $t (type $t'))) + )) +)