current commit
260918.2 · [MakeSharedObjects] Lower externrefs using a dynamically grown table (#9114)
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --make-shared-objects -S -o - | filecheck %s

(module
  ;; Check lowering of basic heap types.
  ;; CHECK:      (type $0 (func (param (ref null (shared none))) (result (ref null (shared none)))))

  ;; CHECK:      (type $1 (func (param (ref (shared none))) (result (ref (shared none)))))

  ;; CHECK:      (type $2 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref (shared i31))) (result (ref (shared i31)))))

  ;; CHECK:      (type $4 (func (param (ref null (shared any))) (result (ref null (shared any)))))

  ;; CHECK:      (type $5 (func (param (ref (shared any))) (result (ref (shared any)))))

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

  ;; CHECK:      (type $7 (func (param (ref (shared eq))) (result (ref (shared eq)))))

  ;; CHECK:      (type $8 (func (param (ref null (shared struct))) (result (ref null (shared struct)))))

  ;; CHECK:      (type $9 (func (param (ref (shared struct))) (result (ref (shared struct)))))

  ;; CHECK:      (type $10 (func (param (ref null (shared array))) (result (ref null (shared array)))))

  ;; CHECK:      (type $11 (func (param (ref (shared array))) (result (ref (shared array)))))

  ;; CHECK:      (func $funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $funcref (param funcref) (result funcref)
    (local funcref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-funcref (type $3) (param $0 (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref (shared i31)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-funcref (param (ref (shared func))) (result (ref (shared func)))
    (local (ref (shared func)))
    (local.get 0)
  )

  ;; CHECK:      (func $nullfuncref (type $0) (param $0 (ref null (shared none))) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared none)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $nullfuncref (param nullfuncref) (result nullfuncref)
    (local nullfuncref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-nullfuncref (type $1) (param $0 (ref (shared none))) (result (ref (shared none)))
  ;; CHECK-NEXT:  (local $1 (ref (shared none)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-nullfuncref (param (ref (shared nofunc))) (result (ref (shared nofunc)))
    (local (ref (shared nofunc)))
    (local.get 0)
  )

  ;; CHECK:      (func $anyref (type $4) (param $0 (ref null (shared any))) (result (ref null (shared any)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared any)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $anyref (param anyref) (result anyref)
    (local anyref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-anyref (type $5) (param $0 (ref (shared any))) (result (ref (shared any)))
  ;; CHECK-NEXT:  (local $1 (ref (shared any)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-anyref (param (ref (shared any))) (result (ref (shared any)))
    (local (ref (shared any)))
    (local.get 0)
  )

  ;; CHECK:      (func $eqref (type $6) (param $0 (ref null (shared eq))) (result (ref null (shared eq)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared eq)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $eqref (param eqref) (result eqref)
    (local eqref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-eqref (type $7) (param $0 (ref (shared eq))) (result (ref (shared eq)))
  ;; CHECK-NEXT:  (local $1 (ref (shared eq)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-eqref (param (ref (shared eq))) (result (ref (shared eq)))
    (local (ref (shared eq)))
    (local.get 0)
  )

  ;; CHECK:      (func $structref (type $8) (param $0 (ref null (shared struct))) (result (ref null (shared struct)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared struct)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $structref (param structref) (result structref)
    (local structref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-structref (type $9) (param $0 (ref (shared struct))) (result (ref (shared struct)))
  ;; CHECK-NEXT:  (local $1 (ref (shared struct)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-structref (param (ref (shared struct))) (result (ref (shared struct)))
    (local (ref (shared struct)))
    (local.get 0)
  )

  ;; CHECK:      (func $arrayref (type $10) (param $0 (ref null (shared array))) (result (ref null (shared array)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared array)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $arrayref (param arrayref) (result arrayref)
    (local arrayref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-arrayref (type $11) (param $0 (ref (shared array))) (result (ref (shared array)))
  ;; CHECK-NEXT:  (local $1 (ref (shared array)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-arrayref (param (ref (shared array))) (result (ref (shared array)))
    (local (ref (shared array)))
    (local.get 0)
  )

  ;; CHECK:      (func $nullref (type $0) (param $0 (ref null (shared none))) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared none)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $nullref (param nullref) (result nullref)
    (local nullref)
    (local.get 0)
  )

  ;; CHECK:      (func $shared-nullref (type $1) (param $0 (ref (shared none))) (result (ref (shared none)))
  ;; CHECK-NEXT:  (local $1 (ref (shared none)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $shared-nullref (param (ref (shared none))) (result (ref (shared none)))
    (local (ref (shared none)))
    (local.get 0)
  )

  ;; TODO: Handle exnref, contref.
)

;; Recursive function types should be updated correctly.
(module
  ;; CHECK:      (type $func (func (param (ref (shared i31))) (result (ref (shared i31)))))
  (type $func (func (param (ref $func)) (result (ref $func))))
  ;; CHECK:      (func $f (type $func) (param $0 (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref (shared i31)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $f (type $func) (param (ref $func)) (result (ref $func))
    (local (ref $func))
    (local.get 0)
  )
)

(module
  ;; Struct and array types should become shared. Function references inside
  ;; them should become shared i31refs. Shared struct and array types should
  ;; remain shared. Function types should become unshared. Distinct shared and
  ;; and unshared types can be merged, but that's ok because their values can
  ;; never flow into the same locations.
  (type $func (func))
  ;; CHECK:      (type $array (shared (array (ref (shared i31)))))

  ;; CHECK:      (type $shared-func (func))

  ;; CHECK:      (type $struct (shared (struct (field (ref (shared i31))) (field i32))))
  (type $struct (struct (field (ref $func)) (field i32)))
  (type $array (array (ref (exact $func))))

  (type $shared-func (shared (func)))
  ;; CHECK:      (type $shared-struct (shared (struct (field (ref null (shared i31))))))
  (type $shared-struct (shared (struct (field (ref null (exact $shared-func))))))
  (type $shared-array (shared (array (ref $shared-func))))

  ;; CHECK:      (type $4 (func (param (ref $struct) (ref $array) (ref $shared-struct) (ref $array))))

  ;; CHECK:      (func $use-types (type $4) (param $0 (ref $struct)) (param $1 (ref $array)) (param $2 (ref $shared-struct)) (param $3 (ref $array))
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $use-types (param (ref $struct) (ref $array) (ref $shared-struct) (ref $shared-array))
    (nop)
  )
  ;; CHECK:      (func $f (type $shared-func)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $f (type $func)
    (nop)
  )
  ;; CHECK:      (func $f-shared (type $shared-func)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $f-shared (type $shared-func)
    (nop)
  )
)

(module
  ;; Rec groups containing mutually recursive struct, array, and function types
  ;; should be preserved.
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $rec-func (func (param (ref $rec-struct))))
    (type $rec-func (func (param (ref $rec-struct))))
    ;; CHECK:       (type $rec-struct (shared (struct (field (ref $rec-array)) (field (ref (shared i31))))))
    (type $rec-struct (struct (field (ref $rec-array)) (field (ref $rec-func))))
    ;; CHECK:       (type $rec-array (shared (array (ref $rec-struct))))
    (type $rec-array (array (ref $rec-struct)))
  )
  ;; CHECK:      (type $3 (func (param (ref $rec-struct) (ref $rec-array) (ref (shared i31)))))

  ;; CHECK:      (func $rec-group (type $3) (param $0 (ref $rec-struct)) (param $1 (ref $rec-array)) (param $2 (ref (shared i31)))
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $rec-group (param (ref $rec-struct) (ref $rec-array) (ref $rec-func))
    (nop)
  )
)

(module
  ;; Function supertypes are preserved.
  ;; CHECK:      (type $parent (sub (func)))
  (type $parent (sub (shared (func))))
  ;; CHECK:      (type $child (sub $parent (func)))
  (type $child (sub $parent (shared (func))))
  ;; CHECK:      (func $f1 (type $parent)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $f1 (type $parent)
    (nop)
  )
  ;; CHECK:      (func $f2 (type $child)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $f2 (type $child)
    (nop)
  )
)

(module
  ;; Struct descriptor and described types become shared correctly.
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $struct (shared (descriptor $desc) (struct (field i32))))
    (type $struct (descriptor $desc) (struct (field i32)))
    ;; CHECK:       (type $desc (shared (describes $struct) (struct (field i32))))
    (type $desc (describes $struct) (struct (field i32)))
  )
  ;; CHECK:      (type $2 (func (param (ref $struct) (ref $desc))))

  ;; CHECK:      (func $descriptors (type $2) (param $0 (ref $struct)) (param $1 (ref $desc))
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $descriptors (param (ref $struct) (ref $desc))
    (nop)
  )
)

;; Check that references to different functions are consistently assigned
;; different indices. This module does not use the references with a call or
;; cast, so it does not get the new table.
(module
  ;; CHECK:      (type $f (func))
  (type $f (func))
  ;; CHECK:      (type $1 (func (result (ref null (shared none)))))

  ;; CHECK:      (type $2 (func (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (result (ref (shared i31)))))

  ;; CHECK:      (func $target1 (type $f)
  ;; CHECK-NEXT: )
  (func $target1 (type $f))
  ;; CHECK:      (func $target2 (type $f)
  ;; CHECK-NEXT: )
  (func $target2 (type $f))

  ;; CHECK:      (func $ref-null-nofunc (type $1) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (ref.null (shared none))
  ;; CHECK-NEXT: )
  (func $ref-null-nofunc (result (ref null nofunc))
    ;; (ref.null nofunc) becomes (ref.null (shared none)).
    (ref.null nofunc)
  )

  ;; CHECK:      (func $ref-null-shared-nofunc (type $1) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (ref.null (shared none))
  ;; CHECK-NEXT: )
  (func $ref-null-shared-nofunc (result (ref null (shared nofunc)))
    ;; Same with a shared nofunc.
    (ref.null (shared nofunc))
  )

  ;; CHECK:      (func $ref-func (type $2) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (ref.i31_shared
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-func (result funcref)
    ;; ref.func becomes a shared i31.
    (ref.func $target1)
  )

  ;; CHECK:      (func $other-ref-func (type $3) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (ref.i31_shared
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $other-ref-func (result (ref (exact $f)))
    ;; Different referenced function, different i31 value.
    (ref.func $target2)
  )

  ;; CHECK:      (func $multiple-ref-func (type $f)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.i31_shared
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.i31_shared
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.i31_shared
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $multiple-ref-func
    ;; Mapping of functions to i31 values should be consistent.
    (drop (ref.func $target1))
    (drop (ref.func $target1))
    (drop (ref.func $target2))
  )
)

;; Test replacement of references in module locations and lowering of calls.
(module
  (type $sig (func (param i32) (result i32)))
  ;; CHECK:      (type $0 (func (result i32)))

  ;; CHECK:      (type $shared-sig (func (param i32) (result i32)))
  (type $shared-sig (shared (func (param i32) (result i32))))

  ;; CHECK:      (type $2 (func))

  ;; CHECK:      (type $struct (shared (struct (field (ref null (shared i31))))))
  (type $struct (struct (field (ref null func))))

  (func $effect (import "" "") (result i32))

  ;; CHECK:      (type $4 (func (param (ref (shared i31)) i32) (result i32)))

  ;; CHECK:      (type $5 (func (param (ref (shared i31))) (result i32)))

  ;; CHECK:      (type $6 (func (param i32 i32) (result i32)))

  ;; CHECK:      (import "" "" (func $effect (type $0) (result i32)))

  ;; CHECK:      (global $g (ref null (shared i31)) (ref.i31_shared
  ;; CHECK-NEXT:  (i32.const 0)
  ;; CHECK-NEXT: ))
  (global $g (ref null func) (ref.func $a))

  ;; CHECK:      (global $g-struct (ref null $struct) (struct.new $struct
  ;; CHECK-NEXT:  (ref.i31_shared
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: ))
  (global $g-struct (ref null $struct) (struct.new $struct (ref.func $b)))

  ;; CHECK:      (table $t-init 1 1 (ref null (shared i31)) (ref.i31_shared
  ;; CHECK-NEXT:  (i32.const 3)
  ;; CHECK-NEXT: ))
  (table $t-init 1 1 (ref null func) (ref.func $c))

  ;; CHECK:      (table $t 1 1 (ref null (shared i31)))
  (table $t 1 1 (ref null $sig))
  ;; CHECK:      (table $t-shared 1 1 (ref null (shared i31)))
  (table $t-shared 1 1 (ref null (shared func)))

  ;; CHECK:      (table $funcs 4 4 funcref)

  ;; CHECK:      (elem $elem (ref null (shared i31)) (item (ref.i31_shared
  ;; CHECK-NEXT:  (i32.const 2)
  ;; CHECK-NEXT: )))
  (elem $elem funcref (ref.func $d))

  ;; CHECK:      (elem $funcs (table $funcs) (i32.const 0) func $a $b $d $c)

  ;; CHECK:      (func $a (type $2)
  ;; CHECK-NEXT: )
  (func $a)
  ;; CHECK:      (func $b (type $2)
  ;; CHECK-NEXT: )
  (func $b)
  ;; CHECK:      (func $c (type $2)
  ;; CHECK-NEXT: )
  (func $c)
  ;; CHECK:      (func $d (type $2)
  ;; CHECK-NEXT: )
  (func $d)

  ;; CHECK:      (func $call-ref (type $4) (param $0 (ref (shared i31))) (param $1 i32) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (local.get $1)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $call-ref (param (ref $sig) i32) (result i32)
    (call_ref $sig (local.get 1) (local.get 0))
  )

  ;; CHECK:      (func $unreachable-call-ref (type $0) (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $unreachable-call-ref (result i32)
    (call_ref $sig (i32.const 0) (unreachable))
  )

  ;; CHECK:      (func $unreachable-call-ref-effect (type $0) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (call $effect)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $unreachable-call-ref-effect (result i32)
    (call_ref $sig (call $effect) (unreachable))
  )

  ;; CHECK:      (func $null-call-ref (type $0) (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $null-call-ref (result i32)
    (call_ref $sig (i32.const 0) (ref.null nofunc))
  )

  ;; CHECK:      (func $null-call-ref-effect (type $0) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (call $effect)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $null-call-ref-effect (result i32)
    (call_ref $sig (call $effect) (ref.null nofunc))
  )

  ;; CHECK:      (func $shared-call-ref (type $5) (param $0 (ref (shared i31))) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (i32.const 42)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $shared-call-ref (param (ref $shared-sig)) (result i32)
    (call_ref $shared-sig (i32.const 42) (local.get 0))
  )

  ;; CHECK:      (func $shared-unreachable-call-ref (type $0) (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $shared-unreachable-call-ref (result i32)
    (call_ref $shared-sig (i32.const 0) (unreachable))
  )

  ;; CHECK:      (func $shared-unreachable-call-ref-effect (type $0) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (call $effect)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $shared-unreachable-call-ref-effect (result i32)
    (call_ref $shared-sig (call $effect) (unreachable))
  )

  ;; CHECK:      (func $shared-null-call-ref (type $0) (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $shared-null-call-ref (result i32)
    (call_ref $shared-sig (i32.const 0) (ref.null (shared nofunc)))
  )

  ;; CHECK:      (func $shared-null-call-ref-effect (type $0) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (call $effect)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $shared-null-call-ref-effect (result i32)
    (call_ref $shared-sig (call $effect) (ref.null (shared nofunc)))
  )

  ;; CHECK:      (func $return-call-ref (type $4) (param $0 (ref (shared i31))) (param $1 i32) (result i32)
  ;; CHECK-NEXT:  (return_call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (local.get $1)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $return-call-ref (param (ref $sig) i32) (result i32)
    (return_call_ref $sig (local.get 1) (local.get 0))
  )

  ;; call_indirect lowering
  ;; CHECK:      (func $call-indirect (type $6) (param $0 i32) (param $1 i32) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (table.get $t
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $call-indirect (param i32 i32) (result i32)
    (call_indirect $t (type $sig) (local.get 0) (local.get 1))
  )

  ;; Unreachable call_indirect lowering.
  ;; CHECK:      (func $unreachable-call-indirect (type $0) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (table.get $t
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $unreachable-call-indirect (result i32)
    (call_indirect $t (type $sig) (i32.const 0) (unreachable))
  )

  ;; call_indirect lowering of shared function.
  ;; CHECK:      (func $shared-call-indirect (type $shared-sig) (param $0 i32) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (i32.const 42)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (table.get $t-shared
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $shared-call-indirect (param i32) (result i32)
    (call_indirect $t-shared (type $shared-sig) (i32.const 42) (local.get 0))
  )

  ;; unreachable call_indirect
  ;; CHECK:      (func $unreachable-param-call-indirect (type $shared-sig) (param $0 i32) (result i32)
  ;; CHECK-NEXT:  (call_indirect $funcs (type $shared-sig)
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (table.get $t
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $unreachable-param-call-indirect (param i32) (result i32)
    (call_indirect $t (type $sig) (unreachable) (local.get 0))
  )
)

;; Test lowering of ref.test and ref.cast.
(module
  (type $sig (func (param i32) (result i32)))
  ;; CHECK:      (type $shared-sig (func (param i32) (result i32)))
  (type $shared-sig (shared (func (param i32) (result i32))))
  ;; CHECK:      (type $1 (func (param (ref null (shared i31))) (result i32)))

  ;; CHECK:      (type $2 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $struct (shared (struct (field i32))))
  (type $struct (struct (field i32)))

  ;; ref.test of funcref
  ;; CHECK:      (type $4 (func (param (ref null (shared i31))) (result (ref (shared i31)))))

  ;; CHECK:      (type $5 (func (param (ref (shared i31))) (result i32)))

  ;; CHECK:      (type $6 (func (result i32)))

  ;; CHECK:      (type $7 (func (param (ref null (shared i31))) (result (ref (shared none)))))

  ;; CHECK:      (type $8 (func (param (ref null (shared i31))) (result (ref null (shared none)))))

  ;; CHECK:      (type $9 (func (param (ref (shared i31))) (result (ref (shared i31)))))

  ;; CHECK:      (type $10 (func (result (ref null (shared i31)))))

  ;; CHECK:      (type $11 (func (param (ref null (shared any))) (result i32)))

  ;; CHECK:      (type $12 (func (param (ref null $struct)) (result i32)))

  ;; CHECK:      (type $13 (func (param (ref null (shared any))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $14 (func (param (ref null $struct)) (result (ref null $struct))))

  ;; CHECK:      (table $funcs 0 0 funcref)

  ;; CHECK:      (func $ref-test-func (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-func (param funcref) (result i32)
    (ref.test (ref func) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-funcref (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-funcref (param funcref) (result i32)
    (ref.test (ref null func) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-nofunc (param funcref) (result i32)
    (ref.test (ref nofunc) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-null-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-null-nofunc (param funcref) (result i32)
    (ref.test (ref null nofunc) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-func (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-func (param (ref null (shared func))) (result i32)
    (ref.test (ref (shared func)) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-funcref (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-funcref (param (ref null (shared func))) (result i32)
    (ref.test (ref null (shared func)) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-nofunc (param (ref null (shared func))) (result i32)
    (ref.test (ref (shared nofunc)) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-null-shared-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-null-shared-nofunc (param (ref null (shared func))) (result i32)
    (ref.test (ref null (shared nofunc)) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-i31 (type $11) (param $0 (ref null (shared any))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-i31 (param (ref null any)) (result i32)
    (ref.test (ref null i31) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-no-nulls (type $5) (param $0 (ref (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:   (table.get $funcs
  ;; CHECK-NEXT:    (i31.get_u
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-no-nulls (param (ref func)) (result i32)
    (ref.test (ref $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-non-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-non-nullable (param funcref) (result i32)
    (ref.test (ref $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref null $shared-sig)
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-nullable (param funcref) (result i32)
    (ref.test (ref null $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-nullable-exact (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref null (exact $shared-sig))
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-nullable-exact (param funcref) (result i32)
    (ref.test (ref null (exact $sig)) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-no-nulls (type $5) (param $0 (ref (shared i31))) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:   (table.get $funcs
  ;; CHECK-NEXT:    (i31.get_u
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-no-nulls (param (ref (shared func))) (result i32)
    (ref.test (ref $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-non-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-non-nullable (param (ref null (shared func))) (result i32)
    (ref.test (ref $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref null $shared-sig)
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-nullable (param (ref null (shared func))) (result i32)
    (ref.test (ref null $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-test-shared-nullable-exact (type $1) (param $0 (ref null (shared i31))) (result i32)
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.test (ref null (exact $shared-sig))
  ;; CHECK-NEXT:     (table.get $funcs
  ;; CHECK-NEXT:      (i31.get_u
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-shared-nullable-exact (param (ref null (shared func))) (result i32)
    (ref.test (ref null (exact $shared-sig)) (local.get 0))
  )


  ;; ref.test with null input
  ;; CHECK:      (func $ref-test-null-input (type $6) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null (shared none))
  ;; CHECK-NEXT:   (ref.null (shared none))
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-null-input (result i32)
    (ref.test (ref null $sig) (ref.null nofunc))
  )

  ;; ref.test with unreachable input
  ;; CHECK:      (func $ref-test-unreachable-input (type $6) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null $shared-sig)
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-unreachable-input (result i32)
    (ref.test (ref null $sig) (unreachable))
  )

  ;; ref.test of non-function type.
  ;; CHECK:      (func $ref-test-non-func (type $12) (param $0 (ref null $struct)) (result i32)
  ;; CHECK-NEXT:  (ref.test (ref null $struct)
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-test-non-func (param (ref null $struct)) (result i32)
    ;; This should not be changed.
    (ref.test (ref null $struct) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-func (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-func (param funcref) (result (ref func))
    (ref.cast (ref func) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-funcref (param funcref) (result (ref null func))
    (ref.cast (ref null func) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-nofunc (type $7) (param $0 (ref null (shared i31))) (result (ref (shared none)))
  ;; CHECK-NEXT:  (ref.cast (ref (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-nofunc (param funcref) (result (ref nofunc))
    (ref.cast (ref nofunc) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-null-nofunc (type $8) (param $0 (ref null (shared i31))) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-null-nofunc (param funcref) (result (ref null nofunc))
    (ref.cast (ref null nofunc) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-func (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-func (param (ref null (shared func))) (result (ref (shared func)))
    (ref.cast (ref (shared func)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-funcref (param (ref null (shared func))) (result (ref null (shared func)))
    (ref.cast (ref null (shared func)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-nofunc (type $7) (param $0 (ref null (shared i31))) (result (ref (shared none)))
  ;; CHECK-NEXT:  (ref.cast (ref (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-nofunc (param (ref null (shared func))) (result (ref (shared nofunc)))
    (ref.cast (ref (shared nofunc)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-null-shared-nofunc (type $8) (param $0 (ref null (shared i31))) (result (ref null (shared none)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared none))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-null-shared-nofunc (param (ref null (shared func))) (result (ref null (shared nofunc)))
    (ref.cast (ref null (shared nofunc)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-i31 (type $13) (param $0 (ref null (shared any))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared i31))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-i31 (param (ref null any)) (result (ref null i31))
    (ref.cast (ref null i31) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-no-nulls (type $9) (param $0 (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (ref.as_non_null
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-no-nulls (param (ref func)) (result (ref $sig))
    (ref.cast (ref $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-non-nullable (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (ref.as_non_null
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-non-nullable (param funcref) (result (ref $sig))
    (ref.cast (ref $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-nullable (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref null $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-nullable (param funcref) (result (ref null $sig))
    (ref.cast (ref null $sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-nullable-exact (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref null (exact $shared-sig))
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-nullable-exact (param funcref) (result (ref null (exact $sig)))
    (ref.cast (ref null (exact $sig)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-no-nulls (type $9) (param $0 (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (ref.as_non_null
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-no-nulls (param (ref (shared func))) (result (ref $shared-sig))
    (ref.cast (ref $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-non-nullable (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (ref.as_non_null
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-non-nullable (param (ref null (shared func))) (result (ref $shared-sig))
    (ref.cast (ref $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-nullable (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref null $shared-sig)
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-nullable (param (ref null (shared func))) (result (ref null $shared-sig))
    (ref.cast (ref null $shared-sig) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-shared-nullable-exact (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $1 (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (ref.is_null
  ;; CHECK-NEXT:    (local.tee $1
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (if (result (ref null (shared i31)))
  ;; CHECK-NEXT:     (ref.test (ref null (exact $shared-sig))
  ;; CHECK-NEXT:      (table.get $funcs
  ;; CHECK-NEXT:       (i31.get_u
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-shared-nullable-exact (param (ref null (shared func))) (result (ref null $shared-sig))
    (ref.cast (ref null (exact $shared-sig)) (local.get 0))
  )

  ;; CHECK:      (func $ref-cast-null-input (type $10) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (ref.cast (ref null (shared none))
  ;; CHECK-NEXT:   (ref.null (shared none))
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-null-input (result (ref null $sig))
    (ref.cast (ref null $sig) (ref.null nofunc))
  )

  ;; CHECK:      (func $ref-cast-unreachable-input (type $10) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (block ;; (replaces unreachable RefCast we can't emit)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-unreachable-input (result (ref null $sig))
    (ref.cast (ref null $sig) (unreachable))
  )

  ;; CHECK:      (func $ref-cast-non-func (type $14) (param $0 (ref null $struct)) (result (ref null $struct))
  ;; CHECK-NEXT:  (ref.cast (ref null $struct)
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-cast-non-func (param (ref null $struct)) (result (ref null $struct))
    ;; This should not be changed.
    (ref.cast (ref null $struct) (local.get 0))
  )

  ;; CHECK:      (func $br-on-cast-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (block $label (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (br_on_cast $label (ref null (shared i31)) (ref null (shared i31))
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-on-cast-funcref (param funcref) (result funcref)
    (block $label (result funcref)
      (br_on_cast $label funcref funcref (local.get 0))
    )
  )

  ;; CHECK:      (func $br-on-cast-fail-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (block $label (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (br_on_cast_fail $label (ref null (shared i31)) (ref null (shared i31))
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-on-cast-fail-funcref (param funcref) (result funcref)
    (block $label (result funcref)
      (br_on_cast_fail $label funcref funcref (local.get 0))
    )
  )

  ;; CHECK:      (func $br-on-cast-nullfuncref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (block $label (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (br_on_cast $label (ref null (shared i31)) (ref null (shared none))
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-on-cast-nullfuncref (param funcref) (result funcref)
    (block $label (result funcref)
      (br_on_cast $label funcref nullfuncref (local.get 0))
    )
  )

  ;; CHECK:      (func $br-on-cast-fail-nullfuncref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (block $label (result (ref null (shared i31)))
  ;; CHECK-NEXT:   (br_on_cast_fail $label (ref null (shared i31)) (ref null (shared none))
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-on-cast-fail-nullfuncref (param funcref) (result funcref)
    (block $label (result funcref)
      (br_on_cast_fail $label funcref nullfuncref (local.get 0))
    )
  )

  ;; TODO: other br_on_cast{_fail} lowering
)

(module
  (type $sig (func (param i32) (result i32)))
  ;; Test that function types in globals, tables, element segments, and tags are updated.
  ;; CHECK:      (type $0 (func (param (ref null (shared i31)))))

  ;; CHECK:      (type $1 (func (param i32) (result (ref null (shared i31)))))

  ;; CHECK:      (global $g (ref null (shared i31)) (ref.null (shared none)))
  (global $g (ref null $sig) (ref.null $sig))
  ;; CHECK:      (table $t 1 1 (ref null (shared i31)) (ref.null (shared none)))
  (table $t 1 1 (ref null $sig) (ref.null $sig))
  ;; CHECK:      (elem $e (ref null (shared i31)) (item (ref.null (shared none))))
  (elem $e (ref null $sig) (ref.null $sig))
  ;; CHECK:      (tag $tag (type $0) (param (ref null (shared i31))))
  (tag $tag (param (ref null $sig)))

  ;; CHECK:      (func $control-types (type $1) (param $0 i32) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (if (result (ref null (shared none)))
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (ref.null (shared none))
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (ref.null (shared none))
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-types (param i32) (result (ref null $sig))
    ;; The result of the If should be updated.
    (if (result (ref null $sig)) (local.get 0)
      (then (ref.null $sig))
      (else (ref.null $sig))
    )
  )
)

(module
  ;; Name collisions with the "funcs" table and "funcs" elements segment are handled correctly.
  ;; CHECK:      (type $f (func))
  (type $f (func))
  ;; CHECK:      (table $funcs 1 1 (ref null (shared i31)))
  (table $funcs 1 1 funcref)
  ;; CHECK:      (table $funcs_1 1 1 funcref)

  ;; CHECK:      (elem $funcs (table $funcs) (i32.const 0) (ref null (shared i31)) (item (ref.i31_shared
  ;; CHECK-NEXT:  (i32.const 0)
  ;; CHECK-NEXT: )))
  (elem $funcs (table $funcs) (i32.const 0) func $target)
  ;; CHECK:      (elem $funcs_1 (table $funcs_1) (i32.const 0) func $target)

  ;; CHECK:      (func $target (type $f)
  ;; CHECK-NEXT: )
  (func $target (type $f))

  ;; CHECK:      (func $name-collision (type $f)
  ;; CHECK-NEXT:  (call_indirect $funcs_1 (type $f)
  ;; CHECK-NEXT:   (i31.get_u
  ;; CHECK-NEXT:    (ref.i31_shared
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $name-collision
    (call_ref $f (ref.func $target))
  )
)

(module
  ;; We want public types to be updated as well.
  (type $sig (func))
  ;; CHECK:      (import "" "" (global $g-funcref (ref null (shared i31))))
  (import "" "" (global $g-funcref funcref))
  ;; CHECK:      (import "" "" (global $g-sig (ref null (shared i31))))
  (import "" "" (global $g-sig (ref null $sig)))
)

(module
  ;; Struct gets of signature fields must be properly refinalized to shared
  ;; i31 after rewriteTypes rewrites the struct types to shared.
  (type $sig (func))
  ;; CHECK:      (type $struct (shared (struct (field (ref (shared i31))))))
  (type $struct (struct (field (ref $sig))))
  ;; CHECK:      (type $1 (func (param (ref $struct)) (result (ref (shared i31)))))

  ;; CHECK:      (func $struct-get (type $1) (param $0 (ref $struct)) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $struct-get (param (ref $struct)) (result (ref $sig))
    (struct.get $struct 0
      (local.get 0)
    )
  )
)

(module
  ;; Extern references entering and exiting via imports and exports are wrapped.
  (import "env" "import_extern" (func $im (param externref i32) (result externref)))

  ;; CHECK:      (type $0 (func (param (ref null (shared i31)) i32) (result (ref null (shared i31)))))

  ;; CHECK:      (type $1 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $2 (func (param externref i32) (result externref)))

  ;; CHECK:      (type $3 (func (param externref) (result externref)))

  ;; CHECK:      (type $4 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $5 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (import "env" "import_extern" (func $im$import (type $2) (param externref i32) (result externref)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_extern" (func $test$export))

  ;; CHECK:      (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 i32) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $extern_to_index
  ;; CHECK-NEXT:   (call $im$import
  ;; CHECK-NEXT:    (call $index_to_extern
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test (type $1) (param $e (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $im
  ;; CHECK-NEXT:   (local.get $e)
  ;; CHECK-NEXT:   (i32.const 42)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (export "export_extern") (param $e externref) (result externref)
    (call $im (local.get $e) (i32.const 42))
  )
)

;; CHECK:      (func $test$export (type $3) (param $0 externref) (result externref)
;; CHECK-NEXT:  (call $index_to_extern
;; CHECK-NEXT:   (call $test
;; CHECK-NEXT:    (call $extern_to_index
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Non-nullable extern references entering and exiting via imports and exports.
  (import "env" "import_nonnull_extern" (func $im (param (ref extern)) (result (ref extern))))

  ;; CHECK:      (type $0 (func (param (ref (shared i31))) (result (ref (shared i31)))))

  ;; CHECK:      (type $1 (func (param (ref extern)) (result (ref extern))))

  ;; CHECK:      (type $2 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (import "env" "import_nonnull_extern" (func $im$import (type $1) (param (ref extern)) (result (ref extern))))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_nonnull_extern" (func $test$export))

  ;; CHECK:      (func $im (type $0) (param $0 (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (ref.as_non_null
  ;; CHECK-NEXT:   (call $extern_to_index
  ;; CHECK-NEXT:    (call $im$import
  ;; CHECK-NEXT:     (ref.cast (ref extern)
  ;; CHECK-NEXT:      (call $index_to_extern
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test (type $0) (param $e (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (call $im
  ;; CHECK-NEXT:   (local.get $e)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (export "export_nonnull_extern") (param $e (ref extern)) (result (ref extern))
    (call $im (local.get $e))
  )
)

;; CHECK:      (func $test$export (type $1) (param $0 (ref extern)) (result (ref extern))
;; CHECK-NEXT:  (ref.cast (ref extern)
;; CHECK-NEXT:   (call $index_to_extern
;; CHECK-NEXT:    (call $test
;; CHECK-NEXT:     (ref.as_non_null
;; CHECK-NEXT:      (call $extern_to_index
;; CHECK-NEXT:       (local.get $0)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Function references (closed world) and shared extern references are NOT wrapped.
  ;; CHECK:      (type $0 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $1 (func (param (ref null (shared extern))) (result (ref null (shared extern)))))

  ;; CHECK:      (import "env" "import_func" (func $im_fn (type $0) (param (ref null (shared i31))) (result (ref null (shared i31)))))
  (import "env" "import_func" (func $im_fn (param funcref) (result funcref)))
  ;; CHECK:      (import "env" "import_shared_extern" (func $im_sh_ext (type $1) (param (ref null (shared extern))) (result (ref null (shared extern)))))
  (import "env" "import_shared_extern" (func $im_sh_ext (param (ref null (shared extern))) (result (ref null (shared extern)))))

  ;; CHECK:      (export "export_func" (func $test_func))

  ;; CHECK:      (export "export_shared_extern" (func $test_shared_extern))

  ;; CHECK:      (func $test_func (type $0) (param $f (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $im_fn
  ;; CHECK-NEXT:   (local.get $f)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test_func (export "export_func") (param $f funcref) (result funcref)
    (call $im_fn (local.get $f))
  )

  ;; CHECK:      (func $test_shared_extern (type $1) (param $e (ref null (shared extern))) (result (ref null (shared extern)))
  ;; CHECK-NEXT:  (call $im_sh_ext
  ;; CHECK-NEXT:   (local.get $e)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test_shared_extern (export "export_shared_extern") (param $e (ref null (shared extern))) (result (ref null (shared extern)))
    (call $im_sh_ext (local.get $e))
  )
)

(module
  ;; String references entering and exiting via imports and exports are wrapped with the extern table.
  (import "env" "import_string" (func $im (param stringref (ref string)) (result stringref)))
  ;; CHECK:      (type $0 (func (param (ref null (shared i31)) (ref (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $1 (func (param (ref null (shared i31)) (ref (shared i31))) (result (ref (shared i31)))))

  ;; CHECK:      (type $2 (func (param stringref (ref string)) (result stringref)))

  ;; CHECK:      (type $3 (func (param stringref (ref string)) (result (ref string))))

  ;; CHECK:      (type $4 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $5 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (import "env" "import_string" (func $im$import (type $2) (param stringref (ref string)) (result stringref)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_string" (func $test$export))

  ;; CHECK:      (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 (ref (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $extern_to_index
  ;; CHECK-NEXT:   (call $im$import
  ;; CHECK-NEXT:    (ref.cast stringref
  ;; CHECK-NEXT:     (call $index_to_extern
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (ref.cast (ref string)
  ;; CHECK-NEXT:     (call $index_to_extern
  ;; CHECK-NEXT:      (local.get $1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test (type $1) (param $s (ref null (shared i31))) (param $s_nn (ref (shared i31))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (call $im
  ;; CHECK-NEXT:    (local.get $s)
  ;; CHECK-NEXT:    (local.get $s_nn)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $s_nn)
  ;; CHECK-NEXT: )
  (func $test (export "export_string") (param $s stringref) (param $s_nn (ref string)) (result (ref string))
    (drop (call $im (local.get $s) (local.get $s_nn)))
    (local.get $s_nn)
  )
)


;; CHECK:      (func $test$export (type $3) (param $0 stringref) (param $1 (ref string)) (result (ref string))
;; CHECK-NEXT:  (ref.cast (ref string)
;; CHECK-NEXT:   (call $index_to_extern
;; CHECK-NEXT:    (call $test
;; CHECK-NEXT:     (call $extern_to_index
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (ref.as_non_null
;; CHECK-NEXT:      (call $extern_to_index
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Tuple results in import and export.
  (import "env" "import_tuple" (func $im (param externref i32) (result externref (ref extern) i32)))

  ;; CHECK:      (type $0 (func (param (ref null (shared i31)) i32) (result (ref null (shared i31)) (ref (shared i31)) i32)))

  ;; CHECK:      (type $1 (func (param externref i32) (result externref (ref extern) i32)))

  ;; CHECK:      (type $2 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (type $4 (func (result (ref null (shared i31)) (ref (shared i31)) i32)))

  ;; CHECK:      (type $5 (func (result externref (ref extern) i32)))

  ;; CHECK:      (import "env" "import_tuple" (func $im$import (type $1) (param externref i32) (result externref (ref extern) i32)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_tuple" (func $test$export))

  ;; CHECK:      (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 i32) (result (ref null (shared i31)) (ref (shared i31)) i32)
  ;; CHECK-NEXT:  (local $2 (tuple externref (ref extern) i32))
  ;; CHECK-NEXT:  (local.set $2
  ;; CHECK-NEXT:   (call $im$import
  ;; CHECK-NEXT:    (call $index_to_extern
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (tuple.make 3
  ;; CHECK-NEXT:   (call $extern_to_index
  ;; CHECK-NEXT:    (tuple.extract 3 0
  ;; CHECK-NEXT:     (local.get $2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (call $extern_to_index
  ;; CHECK-NEXT:     (tuple.extract 3 1
  ;; CHECK-NEXT:      (local.get $2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (tuple.extract 3 2
  ;; CHECK-NEXT:    (local.get $2)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test (type $0) (param $e (ref null (shared i31))) (param $i i32) (result (ref null (shared i31)) (ref (shared i31)) i32)
  ;; CHECK-NEXT:  (call $im
  ;; CHECK-NEXT:   (local.get $e)
  ;; CHECK-NEXT:   (local.get $i)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (export "export_tuple") (param $e externref) (param $i i32) (result externref (ref extern) i32)
    (call $im (local.get $e) (local.get $i))
  )
)

;; CHECK:      (func $test$export (type $1) (param $0 externref) (param $1 i32) (result externref (ref extern) i32)
;; CHECK-NEXT:  (local $2 (tuple (ref null (shared i31)) (ref (shared i31)) i32))
;; CHECK-NEXT:  (local.set $2
;; CHECK-NEXT:   (call $test
;; CHECK-NEXT:    (call $extern_to_index
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:    (local.get $1)
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (tuple.make 3
;; CHECK-NEXT:   (call $index_to_extern
;; CHECK-NEXT:    (tuple.extract 3 0
;; CHECK-NEXT:     (local.get $2)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (ref.cast (ref extern)
;; CHECK-NEXT:    (call $index_to_extern
;; CHECK-NEXT:     (tuple.extract 3 1
;; CHECK-NEXT:      (local.get $2)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (tuple.extract 3 2
;; CHECK-NEXT:    (local.get $2)
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Convert between extern and any (nullable and non-nullable)
  ;; CHECK:      (type $0 (func (param (ref null (shared i31))) (result (ref null (shared any)))))

  ;; CHECK:      (type $1 (func (param (ref (shared i31))) (result (ref (shared any)))))

  ;; CHECK:      (type $2 (func (param (ref null (shared any))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref (shared any))) (result (ref (shared i31)))))

  ;; CHECK:      (type $4 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $5 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (type $6 (func (param (ref null (shared any))) (result externref)))

  ;; CHECK:      (type $7 (func (param externref) (result (ref null (shared any)))))

  ;; CHECK:      (import "env" "any_to_extern" (func $any_to_extern (exact (type $6) (param (ref null (shared any))) (result externref))))

  ;; CHECK:      (import "env" "extern_to_any" (func $extern_to_any (exact (type $7) (param externref) (result (ref null (shared any))))))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (func $any_convert_extern_nullable (type $0) (param $e (ref null (shared i31))) (result (ref null (shared any)))
  ;; CHECK-NEXT:  (call $extern_to_any
  ;; CHECK-NEXT:   (call $index_to_extern
  ;; CHECK-NEXT:    (local.get $e)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $any_convert_extern_nullable (param $e externref) (result anyref)
    (any.convert_extern (local.get $e))
  )

  ;; CHECK:      (func $any_convert_extern_non_nullable (type $1) (param $e (ref (shared i31))) (result (ref (shared any)))
  ;; CHECK-NEXT:  (ref.as_non_null
  ;; CHECK-NEXT:   (call $extern_to_any
  ;; CHECK-NEXT:    (ref.cast (ref extern)
  ;; CHECK-NEXT:     (call $index_to_extern
  ;; CHECK-NEXT:      (local.get $e)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $any_convert_extern_non_nullable (param $e (ref extern)) (result (ref any))
    (any.convert_extern (local.get $e))
  )

  ;; CHECK:      (func $extern_convert_any_nullable (type $2) (param $a (ref null (shared any))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $extern_to_index
  ;; CHECK-NEXT:   (call $any_to_extern
  ;; CHECK-NEXT:    (local.get $a)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $extern_convert_any_nullable (param $a anyref) (result externref)
    (extern.convert_any (local.get $a))
  )

  ;; CHECK:      (func $extern_convert_any_non_nullable (type $3) (param $a (ref (shared any))) (result (ref (shared i31)))
  ;; CHECK-NEXT:  (ref.as_non_null
  ;; CHECK-NEXT:   (call $extern_to_index
  ;; CHECK-NEXT:    (call $any_to_extern
  ;; CHECK-NEXT:     (local.get $a)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $extern_convert_any_non_nullable (param $a (ref any)) (result (ref extern))
    (extern.convert_any (local.get $a))
  )
)

;; CHECK:      (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Re-export an imported function with externrefs.
  (import "env" "import_and_export" (func $im (param externref) (result externref)))
  (export "export_import" (func $im))
)

;; CHECK:      (type $0 (func (param externref) (result externref)))

;; CHECK:      (type $1 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

;; CHECK:      (type $2 (func (param externref) (result (ref null (shared i31)))))

;; CHECK:      (type $3 (func (param (ref null (shared i31))) (result externref)))

;; CHECK:      (import "env" "import_and_export" (func $im$import (type $0) (param externref) (result externref)))

;; CHECK:      (table $externs 0 externref)

;; CHECK:      (export "export_import" (func $im$export))

;; CHECK:      (func $im (type $1) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT:  (call $extern_to_index
;; CHECK-NEXT:   (call $im$import
;; CHECK-NEXT:    (call $index_to_extern
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $im$export (type $0) (param $0 externref) (result externref)
;; CHECK-NEXT:  (call $index_to_extern
;; CHECK-NEXT:   (call $im
;; CHECK-NEXT:    (call $extern_to_index
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Multiple exports of the same function are deduplicated.
  ;; CHECK:      (type $0 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))

  ;; CHECK:      (type $1 (func (param externref) (result externref)))

  ;; CHECK:      (type $2 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "exp1" (func $multi$export))

  ;; CHECK:      (export "exp2" (func $multi$export))

  ;; CHECK:      (func $multi (type $0) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
  ;; CHECK-NEXT:  (local.get $0)
  ;; CHECK-NEXT: )
  (func $multi (export "exp1") (export "exp2") (param externref) (result externref)
    (local.get 0)
  )
)

;; CHECK:      (func $multi$export (type $1) (param $0 externref) (result externref)
;; CHECK-NEXT:  (call $index_to_extern
;; CHECK-NEXT:   (call $multi
;; CHECK-NEXT:    (call $extern_to_index
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Tuple result without externrefs should not unpack and repack.
  (import "env" "import_no_ext_tuple" (func $im_tuple (param externref) (result i32 i64)))
  ;; CHECK:      (type $0 (func (param (ref null (shared i31))) (result i32 i64)))

  ;; CHECK:      (type $1 (func (param externref) (result i32 i64)))

  ;; CHECK:      (type $2 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $3 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (import "env" "import_no_ext_tuple" (func $im_tuple$import (type $1) (param externref) (result i32 i64)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_no_ext_tuple" (func $test_no_ext_tuple$export))

  ;; CHECK:      (func $im_tuple (type $0) (param $0 (ref null (shared i31))) (result i32 i64)
  ;; CHECK-NEXT:  (call $im_tuple$import
  ;; CHECK-NEXT:   (call $index_to_extern
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test_no_ext_tuple (type $0) (param $0 (ref null (shared i31))) (result i32 i64)
  ;; CHECK-NEXT:  (call $im_tuple
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test_no_ext_tuple (export "export_no_ext_tuple") (param externref) (result i32 i64)
    (call $im_tuple (local.get 0))
  )
)

;; CHECK:      (func $test_no_ext_tuple$export (type $1) (param $0 externref) (result i32 i64)
;; CHECK-NEXT:  (call $test_no_ext_tuple
;; CHECK-NEXT:   (call $extern_to_index
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Mixed struct and externref at boundary.
  ;; CHECK:      (type $struct (shared (struct (field (mut i32)))))
  (type $struct (struct (field (mut i32))))
  (import "env" "import_mixed" (func $im_mixed (param (ref $struct) externref) (result (ref $struct) externref)))
  ;; CHECK:      (type $1 (func (param (ref $struct) (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))))

  ;; CHECK:      (type $2 (func (param (ref $struct) externref) (result (ref $struct) externref)))

  ;; CHECK:      (type $3 (func (param externref) (result (ref null (shared i31)))))

  ;; CHECK:      (type $4 (func (param (ref null (shared i31))) (result externref)))

  ;; CHECK:      (type $5 (func (result (ref $struct) (ref null (shared i31)))))

  ;; CHECK:      (type $6 (func (result (ref $struct) externref)))

  ;; CHECK:      (import "env" "import_mixed" (func $im_mixed$import (type $2) (param (ref $struct) externref) (result (ref $struct) externref)))

  ;; CHECK:      (table $externs 0 externref)

  ;; CHECK:      (export "export_mixed" (func $test_mixed$export))

  ;; CHECK:      (func $im_mixed (type $1) (param $0 (ref $struct)) (param $1 (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))
  ;; CHECK-NEXT:  (local $2 (tuple (ref $struct) externref))
  ;; CHECK-NEXT:  (local.set $2
  ;; CHECK-NEXT:   (call $im_mixed$import
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:    (call $index_to_extern
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (tuple.make 2
  ;; CHECK-NEXT:   (tuple.extract 2 0
  ;; CHECK-NEXT:    (local.get $2)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $extern_to_index
  ;; CHECK-NEXT:    (tuple.extract 2 1
  ;; CHECK-NEXT:     (local.get $2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )

  ;; CHECK:      (func $test_mixed (type $1) (param $0 (ref $struct)) (param $1 (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))
  ;; CHECK-NEXT:  (call $im_mixed
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:   (local.get $1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test_mixed (export "export_mixed") (param (ref $struct) externref) (result (ref $struct) externref)
    (call $im_mixed (local.get 0) (local.get 1))
  )
)
;; CHECK:      (func $test_mixed$export (type $2) (param $0 (ref $struct)) (param $1 externref) (result (ref $struct) externref)
;; CHECK-NEXT:  (local $2 (tuple (ref $struct) (ref null (shared i31))))
;; CHECK-NEXT:  (local.set $2
;; CHECK-NEXT:   (call $test_mixed
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:    (call $extern_to_index
;; CHECK-NEXT:     (local.get $1)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (tuple.make 2
;; CHECK-NEXT:   (tuple.extract 2 0
;; CHECK-NEXT:    (local.get $2)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (call $index_to_extern
;; CHECK-NEXT:    (tuple.extract 2 1
;; CHECK-NEXT:     (local.get $2)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $extern_to_index (type $3) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT:  (local $1 i32)
;; CHECK-NEXT:  (if (result (ref null (shared i31)))
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null (shared none))
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (if (result (ref (shared i31)))
;; CHECK-NEXT:     (i32.ge_s
;; CHECK-NEXT:      (local.tee $1
;; CHECK-NEXT:       (table.grow $externs
;; CHECK-NEXT:        (local.get $0)
;; CHECK-NEXT:        (i32.const 1)
;; CHECK-NEXT:       )
;; CHECK-NEXT:      )
;; CHECK-NEXT:      (i32.const 0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (then
;; CHECK-NEXT:      (ref.i31_shared
;; CHECK-NEXT:       (local.get $1)
;; CHECK-NEXT:      )
;; CHECK-NEXT:     )
;; CHECK-NEXT:     (else
;; CHECK-NEXT:      (unreachable)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $index_to_extern (type $4) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT:  (if (result externref)
;; CHECK-NEXT:   (ref.is_null
;; CHECK-NEXT:    (local.get $0)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (then
;; CHECK-NEXT:    (ref.null noextern)
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (else
;; CHECK-NEXT:    (table.get $externs
;; CHECK-NEXT:     (i31.get_u
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )