blob: e102107e37f7ef6eb78ed9235ddc45b89c8e402e [file] [edit]
(module
;; Two structs, A and B, each of which has a subtype.
(rec
(type $A (sub (struct)))
(type $A2 (sub $A (struct)))
(type $B (sub (struct)))
(type $B2 (sub $B(struct)))
)
;; Two imports, one which will be referenced.
(import "module" "base" (func $import (param i32 anyref) (result eqref)))
(import "module" "base" (func $import-reffed (param i32 anyref) (result eqref)))
;; Two exports, one which will be referenced.
(func $export (export "export") (param $0 i32) (param $1 anyref) (result eqref)
;; Add the refs.
(drop
(ref.func $import-reffed)
)
(drop
(ref.func $export-reffed)
)
;; Call the imports.
(drop
(call $import
(i32.const 10)
;; Send $A. We can refine the anyref to $A or $A2 (but not $B or $B2).
(struct.new $A)
)
)
(drop
(call $import-reffed
(i32.const 20)
(struct.new $A)
)
)
;; Return $B. We can refine the eqref to $B or $B2 (but not $A or $A2).
(struct.new $B)
)
(func $export-reffed (export "export-reffed") (param $0 i32) (param $1 anyref) (result eqref)
(struct.new $A)
)
;; An export without a ref.func but that has a tail call, which also prevents
;; us from refining its results. The called function and the caller both
;; return nullref initially, and each might be refined to a conflicting type,
;; if we are not careful here.
(func $tail-called (export "tail-called") (result nullref)
(ref.null $A)
)
(func $tail-caller (export "tail-caller") (param $x i32) (result nullref)
(if
(local.get $x)
(then
(return
(ref.null $B)
)
)
)
(return_call $tail-called)
)
)