Skip to content

Implement type imports and exports #7330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Prev Previous commit
Next Next commit
Add tests
  • Loading branch information
vouillon committed Feb 26, 2025
commit 48cc48e06a64997fe97749b9368af4f4a8412d20
5 changes: 4 additions & 1 deletion scripts/test/fuzzing.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@
'stack_switching_suspend.wast',
'stack_switching_resume.wast',
'stack_switching_resume_throw.wast',
'stack_switching_switch.wast'
'stack_switching_switch.wast',
# TODO: fuzzer support for type imports
'type-imports.wast',
'type-imports.wat'
]


Expand Down
130 changes: 130 additions & 0 deletions test/lit/basic/type-imports.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-opt %s -all -o %t.text.wast -g -S
;; RUN: wasm-as %s -all -g -o %t.wasm
;; RUN: wasm-dis %t.wasm -all -o %t.bin.wast
;; RUN: wasm-as %s -all -o %t.nodebug.wasm
;; RUN: wasm-dis %t.nodebug.wasm -all -o %t.bin.nodebug.wast
;; RUN: cat %t.text.wast | filecheck %s --check-prefix=CHECK
;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK
;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG

(module

;; Simple import
;; CHECK: (import "env" "t1" (type $t1 (sub eq)))
(import "env" "t1" (type $t1 (sub eq)))

;; Import with omitted typetype
;; CHECK: (import "env" "t2" (type $t2 (sub any)))
(import "env" "t2" (type $t2))

;; Alternative synyax with both import and export
(type $t3 (export "t3") (import "env" "t3") (sub struct))

;; Use an imported type in a type
;; CHECK: (import "env" "t3" (type $t3 (sub struct)))

;; CHECK: (type $t4 (array (ref $t1)))
(type $t4 (array (field (ref $t1))))

;; CHECK: (type $t5 (struct (field (ref $t1))))
(type $t5 (export "t5") (struct (field (ref $t1))))

;; Import function with imported types
;; CHECK: (type $5 (func (param (ref $t1)) (result (ref $t2))))

;; CHECK: (type $6 (func (param (ref eq) (ref $t2) (ref $t3) (ref $t4)) (result (ref $t2))))

;; CHECK: (type $7 (func (param (ref $t3)) (result (ref struct))))

;; CHECK: (import "env" "g" (func $g (type $5) (param (ref $t1)) (result (ref $t2))))
(import "env" "g" (func $g (param (ref $t1)) (result (ref $t2))))

;; Cast and function call involving imported types
(func (export "f1")
(param $x (ref eq)) (param (ref $t2) (ref $t3) (ref $t4)) (result (ref $t2))
(call $g
(ref.cast (ref $t1)
(local.get $x)
)
)
)

;; Check that the imported type is a subtype of its bound
(func (export "f2") (param $x (ref $t3)) (result (ref struct))
(local.get $x)
)

;; Reexport an imported type
;; CHECK: (export "t3" (type $t3))

;; CHECK: (export "t5" (type $t5))

;; CHECK: (export "t2" (type $t2))
(export "t2" (type $t2))

;; Export a type defined in this module
;; CHECK: (export "t4" (type $t4))
(export "t4" (type $t4))

;; Export an abstract heap type
(export "t6" (type extern))
)
;; CHECK: (export "f1" (func $0))

;; CHECK: (export "f2" (func $1))

;; CHECK: (func $0 (type $6) (param $x (ref eq)) (param $1 (ref $t2)) (param $2 (ref $t3)) (param $3 (ref $t4)) (result (ref $t2))
;; CHECK-NEXT: (call $g
;; CHECK-NEXT: (ref.cast (ref $t1)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $1 (type $7) (param $x (ref $t3)) (result (ref struct))
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )

;; CHECK-BIN-NODEBUG: (import "env" "t1" (type $0 (sub eq)))

;; CHECK-BIN-NODEBUG: (import "env" "t2" (type $1 (sub any)))

;; CHECK-BIN-NODEBUG: (import "env" "t3" (type $2 (sub struct)))

;; CHECK-BIN-NODEBUG: (type $3 (array (ref $0)))

;; CHECK-BIN-NODEBUG: (type $4 (struct (field (ref $0))))

;; CHECK-BIN-NODEBUG: (type $5 (func (param (ref $0)) (result (ref $1))))

;; CHECK-BIN-NODEBUG: (type $6 (func (param (ref eq) (ref $1) (ref $2) (ref $3)) (result (ref $1))))

;; CHECK-BIN-NODEBUG: (type $7 (func (param (ref $2)) (result (ref struct))))

;; CHECK-BIN-NODEBUG: (import "env" "g" (func $fimport$0 (type $5) (param (ref $0)) (result (ref $1))))

;; CHECK-BIN-NODEBUG: (export "t3" (type $2))

;; CHECK-BIN-NODEBUG: (export "t5" (type $4))

;; CHECK-BIN-NODEBUG: (export "t2" (type $1))

;; CHECK-BIN-NODEBUG: (export "t4" (type $3))

;; CHECK-BIN-NODEBUG: (export "f1" (func $0))

;; CHECK-BIN-NODEBUG: (export "f2" (func $1))

;; CHECK-BIN-NODEBUG: (func $0 (type $6) (param $0 (ref eq)) (param $1 (ref $1)) (param $2 (ref $2)) (param $3 (ref $3)) (result (ref $1))
;; CHECK-BIN-NODEBUG-NEXT: (call $fimport$0
;; CHECK-BIN-NODEBUG-NEXT: (ref.cast (ref $0)
;; CHECK-BIN-NODEBUG-NEXT: (local.get $0)
;; CHECK-BIN-NODEBUG-NEXT: )
;; CHECK-BIN-NODEBUG-NEXT: )
;; CHECK-BIN-NODEBUG-NEXT: )

;; CHECK-BIN-NODEBUG: (func $1 (type $7) (param $0 (ref $2)) (result (ref struct))
;; CHECK-BIN-NODEBUG-NEXT: (local.get $0)
;; CHECK-BIN-NODEBUG-NEXT: )
133 changes: 133 additions & 0 deletions test/lit/merge/type-imports.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: wasm-merge %s first %s.second second -all -S -o - | filecheck %s

(module
;; Bound to an abstract heap type
(import "second" "t1" (type $t1))

;; Bound to a concrete heap type
(import "second" "t2" (type $t2))

;; Bound to an imported type
;; CHECK: (import "third" "t3" (type $t3 (sub struct)))
(import "second" "t3" (type $t3))

;; Left unbound
;; CHECK: (import "third" "t4" (type $t4 (sub any)))
(import "third" "t4" (type $t4))

;; Check the import of a function using imported types
(import "second" "g" (func $g (param (ref $t2))))

;; Check that the function parameters are updated
(func (export "f") (param (ref $t1) (ref $t2) (ref $t3) (ref $t4))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you give these functions $names, then the test output update script should be able to match them up with functions in the output and put them next to each other.

)

;; Check that types in instructions are also updated
(func (export "g1") (param $x (ref any)) (result (ref $t1))
(ref.cast (ref $t1)
(local.get $x)
)
)

(func (export "g2") (param $x (ref any)) (result (ref $t2))
(ref.cast (ref $t2)
(local.get $x)
)
)

(func (export "g3") (param $x (ref any)) (result (ref $t3))
(ref.cast (ref $t3)
(local.get $x)
)
)

(func (export "g4") (param $x (ref any)) (result (ref $t4))
(ref.cast (ref $t4)
(local.get $x)
)
)

;; Check that recursive types are preserved
(rec
;; CHECK: (type $t2 (array i8))

;; CHECK: (rec
;; CHECK-NEXT: (type $r1 (struct (field (ref $r1)) (field (ref $r2)) (field (ref eq))))
(type $r1 (struct (field (ref $r1) (ref $r2) (ref $t1))))
;; CHECK: (type $r2 (struct (field (ref $r1)) (field (ref $r2)) (field (ref $t2))))
(type $r2 (struct (field (ref $r1) (ref $r2) (ref $t2))))
)

(func (export "h") (param $x (ref eq)) (result (ref $r1))
(ref.cast (ref $r1) (local.get $x)))
)

;; CHECK: (type $5 (func (param (ref eq) (ref $t2) (ref $t3) (ref $t4))))

;; CHECK: (type $6 (func (param (ref any)) (result (ref eq))))

;; CHECK: (type $7 (func (param (ref any)) (result (ref $t2))))

;; CHECK: (type $8 (func (param (ref any)) (result (ref $t3))))

;; CHECK: (type $9 (func (param (ref any)) (result (ref $t4))))

;; CHECK: (type $10 (func (param (ref eq)) (result (ref $r1))))

;; CHECK: (type $11 (func (param (ref $t2))))

;; CHECK: (export "t2" (type $t2))

;; CHECK: (export "t3" (type $t3))

;; CHECK: (export "f" (func $0))

;; CHECK: (export "g1" (func $1))

;; CHECK: (export "g2" (func $2))

;; CHECK: (export "g3" (func $3))

;; CHECK: (export "g4" (func $4))

;; CHECK: (export "h" (func $5))

;; CHECK: (export "g" (func $g_7))

;; CHECK: (func $0 (type $5) (param $0 (ref eq)) (param $1 (ref $t2)) (param $2 (ref $t3)) (param $3 (ref $t4))
;; CHECK-NEXT: )

;; CHECK: (func $1 (type $6) (param $x (ref any)) (result (ref eq))
;; CHECK-NEXT: (ref.cast (ref eq)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $2 (type $7) (param $x (ref any)) (result (ref $t2))
;; CHECK-NEXT: (ref.cast (ref $t2)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $3 (type $8) (param $x (ref any)) (result (ref $t3))
;; CHECK-NEXT: (ref.cast (ref $t3)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $4 (type $9) (param $x (ref any)) (result (ref $t4))
;; CHECK-NEXT: (ref.cast (ref $t4)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $5 (type $10) (param $x (ref eq)) (result (ref $r1))
;; CHECK-NEXT: (ref.cast (ref $r1)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )

;; CHECK: (func $g_7 (type $11) (param $0 (ref $t2))
;; CHECK-NEXT: )
7 changes: 7 additions & 0 deletions test/lit/merge/type-imports.wat.second
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(module
(export "t1" (type eq))
(import "third" "t3" (type $t3 (sub struct)))
(type $t2 (export "t2") (array i8))
(export "t3" (type $t3))
(func $g (export "g") (param (ref $t2)))
)
Loading