blob: 49330fc7b84aeccc0afbece2dccc9c5ec38ad956 [file] [log] [blame] [edit]
;; TODO: Use the upstream version from the custom descriptors proposal.
(module
(type $f (func))
(import "" "" (func $1 (exact (type 0))))
(import "" "" (func $2 (exact (type $f) (param) (result))))
(import "" "" (func $3 (exact (type $f))))
(import "" "" (func $4 (exact (type 1)))) ;; Implicitly defined next
(import "" "" (func $5 (exact (param i32) (result i64))))
(func $6 (import "" "") (exact (type 0)))
(func $7 (import "" "") (exact (type $f) (param) (result)))
(func $8 (import "" "") (exact (type $f)))
(func $9 (import "" "") (exact (type 2))) ;; Implicitly defined next
(func $10 (import "" "") (exact (param i64) (result i32)))
(global (ref (exact $f)) (ref.func $1))
(global (ref (exact $f)) (ref.func $2))
(global (ref (exact $f)) (ref.func $3))
(global (ref (exact 1)) (ref.func $4))
(global (ref (exact 1)) (ref.func $5))
(global (ref (exact $f)) (ref.func $6))
(global (ref (exact $f)) (ref.func $7))
(global (ref (exact $f)) (ref.func $8))
(global (ref (exact 2)) (ref.func $9))
(global (ref (exact 2)) (ref.func $10))
)
;; References to inexact imports are not exact.
(assert_invalid
(module
(type $f (func))
(import "" "" (func $1 (type $f)))
(global (ref (exact $f)) (ref.func $1))
)
"type mismatch"
)
(assert_invalid
(module
(type $f (func))
(import "" "" (func $1 (type $f)))
(elem declare func $1)
(func (result (ref (exact $f)))
(ref.func $1)
)
)
"type mismatch"
)
;; Inexact imports can still be referenced inexactly, though.
(module
(type $f (func))
(import "" "" (func $1 (type $f)))
(global (ref $f) (ref.func $1))
(func (result (ref $f))
(ref.func $1)
)
)
;; Define a function and export it exactly.
(module $A
(type $f (func))
(func (export "f") (type $f))
)
(register "A")
;; Import and re-export inexactly.
(module $B
(type $f (func))
(func (export "f") (import "A" "f") (type $f))
)
(register "B")
;; The export from A is exact.
(module
(type $f (func))
(import "A" "f" (func (exact (type $f))))
)
;; The export from B is _statically_ inexact, but instantiation checks
;; the dynamic types of imports, so this link still succeeds.
(module
(type $f (func))
(import "B" "f" (func (exact (type $f))))
)
;; Even when the function is imported inexactly, it can still be cast to its
;; exact type.
(module
(type $f (func))
(import "A" "f" (func $1 (type $f)))
(elem declare func $1)
(func (export "exact-test") (result i32)
(ref.test (ref (exact $f)) (ref.func $1))
)
(func (export "exact-cast") (result (ref (exact $f)))
(ref.cast (ref (exact $f)) (ref.func $1))
)
(func (export "exact-br-on-cast") (result funcref)
(br_on_cast 0 funcref (ref (exact $f)) (ref.func $1))
(unreachable)
)
(func (export "exact-br-on-cast-fail") (result funcref)
(block (result funcref)
(br_on_cast_fail 0 funcref (ref (exact $f)) (ref.func $1))
(return)
)
(unreachable)
)
)
(assert_return (invoke "exact-test") (i32.const 1))
(assert_return (invoke "exact-cast") (ref.func))
(assert_return (invoke "exact-br-on-cast") (ref.func))
(assert_return (invoke "exact-br-on-cast-fail") (ref.func))
;; Define a function with a type that has a supertype.
(module $C
(type $super (sub (func)))
(type $sub (sub $super (func)))
(func (export "f") (type $sub))
(func (export "g") (type $super))
)
(register "C")
;; TODO: Fix function type checking on linking.
;; ;; We should not be able to import the function with the exact supertype.
;; (assert_unlinkable
;; (module
;; (type $super (sub (func)))
;; (type $sub (sub $super (func)))
;; (import "C" "f" (func (exact (type $super))))
;; )
;; "incompatible import type"
;; )
;; But we can still import it and re-export it inexactly with the supertype.
(module $D
(type $super (sub (func)))
(type $sub (sub $super (func)))
(import "C" "f" (func (type $super)))
(export "f" (func 0))
)
(register "D")
;; As before, we can still import the function with its real dynamic type.
(module
(type $super (sub (func)))
(type $sub (sub $super (func)))
(import "D" "f" (func (exact (type $sub))))
)
;; As before, even when the function is imported inexactly (this time with its
;; supertype), it can still be cast to its exact type.
(module
(type $super (sub (func)))
(type $sub (sub $super (func)))
(import "C" "f" (func $1 (type $super)))
(elem declare func $1)
(func (export "exact-test") (result i32)
(ref.test (ref (exact $sub)) (ref.func $1))
)
(func (export "exact-cast") (result (ref (exact $sub)))
(ref.cast (ref (exact $sub)) (ref.func $1))
)
(func (export "exact-br-on-cast") (result funcref)
(br_on_cast 0 funcref (ref (exact $sub)) (ref.func $1))
(unreachable)
)
(func (export "exact-br-on-cast-fail") (result funcref)
(block (result funcref)
(br_on_cast_fail 0 funcref (ref (exact $sub)) (ref.func $1))
(return)
)
(unreachable)
)
)
(assert_return (invoke "exact-test") (i32.const 1))
(assert_return (invoke "exact-cast") (ref.func))
(assert_return (invoke "exact-br-on-cast") (ref.func))
(assert_return (invoke "exact-br-on-cast-fail") (ref.func))
;; But if we import a function whose dynamic type is the supertype, the same
;; casts will fail.
(module
(type $super (sub (func)))
(type $sub (sub $super (func)))
(import "C" "g" (func $1 (type $super)))
(elem declare func $1)
(func (export "exact-test") (result i32)
(ref.test (ref (exact $sub)) (ref.func $1))
)
(func (export "exact-cast") (result (ref (exact $sub)))
(ref.cast (ref (exact $sub)) (ref.func $1))
)
(func (export "exact-br-on-cast") (result funcref)
(br_on_cast 0 funcref (ref (exact $sub)) (ref.func $1))
(unreachable)
)
(func (export "exact-br-on-cast-fail") (result funcref)
(block (result funcref)
(br_on_cast_fail 0 funcref (ref (exact $sub)) (ref.func $1))
(return)
)
(unreachable)
)
)
(assert_return (invoke "exact-test") (i32.const 0))
(assert_trap (invoke "exact-cast") "cast failure")
(assert_trap (invoke "exact-br-on-cast") "unreachable")
(assert_trap (invoke "exact-br-on-cast-fail") "unreachable")
;; Test the binary format
;; Exact function imports use 0x20.
(module binary
"\00asm" "\01\00\00\00"
"\01" ;; Type section id
"\04" ;; Type section length
"\01" ;; Types vector length
"\60" ;; Function
"\00" ;; Number of params
"\00" ;; Number of results
"\02" ;; Import section id
"\05" ;; Import section length
"\01" ;; Import vector length
"\00" ;; Module name length
"\00" ;; Base name length
"\20" ;; Exact function
"\00" ;; Type index
)
;; 0x20 is malformed in exports.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01" ;; Type section id
"\04" ;; Type section length
"\01" ;; Types vector length
"\60" ;; Function
"\00" ;; Number of params
"\00" ;; Number of results
"\03" ;; Function section id
"\02" ;; Function section length
"\01" ;; Function vector length
"\00" ;; Type index
"\07" ;; Export section id
"\04" ;; Export section length
"\01" ;; Export vector length
"\00" ;; Name length
"\20" ;; Exact func (malformed)
"\00" ;; Function index
"\0a" ;; Code section
"\04" ;; Code section length
"\01" ;; Code vector length
"\02" ;; Function length
"\00" ;; Type index
"\0b" ;; End
)
"malformed export kind"
)