;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: foreach %s %t wasm-opt --experimental-type-generalizing -all -S -o - | filecheck %s

(module
 ;; CHECK:      (type $void (func))
 (type $void (func))

 ;; CHECK:      (type $1 (func (result eqref)))

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

 ;; CHECK:      (type $3 (func (param eqref anyref)))

 ;; CHECK:      (type $4 (func (param anyref)))

 ;; CHECK:      (type $5 (func (param i31ref)))

 ;; CHECK:      (type $6 (func (param anyref eqref)))

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

 ;; CHECK:      (type $8 (func (result nullref)))

 ;; CHECK:      (type $9 (func (result structref)))

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

 ;; CHECK:      (type $11 (func (param (ref noextern)) (result anyref)))

 ;; CHECK:      (type $12 (func (param (ref noextern)) (result (ref any))))

 ;; CHECK:      (type $13 (func (result externref)))

 ;; CHECK:      (type $14 (func (result (ref extern))))

 ;; CHECK:      (type $15 (func (param anyref anyref)))

 ;; CHECK:      (global $global-eq (mut eqref) (ref.null none))
 (global $global-eq (mut eqref) (ref.null none))

 ;; CHECK:      (global $global-i32 (mut i32) (i32.const 0))
 (global $global-i32 (mut i32) (i32.const 0))

 ;; CHECK:      (table $func-table 0 0 funcref)
 (table $func-table 0 0 funcref)

 ;; CHECK:      (table $eq-table 0 0 eqref)
 (table $eq-table 0 0 eqref)

 ;; CHECK:      (elem declare func $ref-func)

 ;; CHECK:      (func $unconstrained (type $void)
 ;; CHECK-NEXT:  (local $x i32)
 ;; CHECK-NEXT:  (local $y anyref)
 ;; CHECK-NEXT:  (local $z (tuple anyref i32))
 ;; CHECK-NEXT: )
 (func $unconstrained
  ;; This non-ref local should be unmodified
  (local $x i32)
  ;; There is no constraint on the type of this local, so make it top.
  (local $y i31ref)
  ;; We cannot optimize tuple locals yet, so leave it unchanged.
  (local $z (tuple anyref i32))
 )

 ;; CHECK:      (func $implicit-return (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (local.get $var)
 ;; CHECK-NEXT: )
 (func $implicit-return (result eqref)
  ;; This will be optimized, but only to eqref because of the constraint from the
  ;; implicit return.
  (local $var i31ref)
  (local.get $var)
 )

 ;; CHECK:      (func $implicit-return-unreachable (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $implicit-return-unreachable (result eqref)
  ;; We will optimize this all the way to anyref because we don't analyze
  ;; unreachable code. This would not validate if we didn't run DCE first.
  (local $var i31ref)
  (unreachable)
  (local.get $var)
 )

 ;; CHECK:      (func $if (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $x eqref)
 ;; CHECK-NEXT:  (local $y eqref)
 ;; CHECK-NEXT:  (if (result eqref)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (then
 ;; CHECK-NEXT:    (local.get $x)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (else
 ;; CHECK-NEXT:    (local.get $y)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $if (result eqref)
  (local $x i31ref)
  (local $y i31ref)
  (if (result i31ref)
   (i32.const 0)
   ;; Require that typeof($x) <: eqref.
   (then
    (local.get $x)
   )
   ;; Require that typeof($y) <: eqref.
   (else
    (local.get $y)
   )
  )
 )

 ;; CHECK:      (func $loop (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (loop (result eqref)
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $loop (result eqref)
  (local $var i31ref)
  ;; Require that typeof($var) <: eqref.
  (loop (result i31ref)
   (local.get $var)
  )
 )

 ;; CHECK:      (func $br-sent (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var1 anyref)
 ;; CHECK-NEXT:  (local $var2 eqref)
 ;; CHECK-NEXT:  (block $l (result eqref)
 ;; CHECK-NEXT:   (block
 ;; CHECK-NEXT:    (drop
 ;; CHECK-NEXT:     (local.get $var1)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:    (br $l
 ;; CHECK-NEXT:     (local.get $var2)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br-sent (result eqref)
  (local $var1 i31ref)
  (local $var2 i31ref)
  (block $l (result i31ref)
   ;; The call will be DCEd out, but this test and the implementation for `br`
   ;; should be forward-compatible with a future where we do not have to run DCE
   ;; before this pass.
   (call $helper-any_any
    ;; No requirements on $var1
    (local.get $var1)
    ;; Require that typeof($var2) <: eqref.
    (br $l
     (local.get $var2)
    )
   )
  )
 )

 ;; CHECK:      (func $br-no-sent (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (block $l
 ;; CHECK-NEXT:   (block
 ;; CHECK-NEXT:    (drop
 ;; CHECK-NEXT:     (local.get $var)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:    (br $l)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br-no-sent
  (local $var i31ref)
  (block $l
   ;; This call is DCEd out just like in the previous test.
   (call $helper-any_any
    ;; No requirements on $var
    (local.get $var)
    (br $l)
   )
  )
 )

 ;; CHECK:      (func $br_table-sent (type $3) (param $eq eqref) (param $any anyref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (local.set $eq
 ;; CHECK-NEXT:   (block $l1 (result eqref)
 ;; CHECK-NEXT:    (local.set $any
 ;; CHECK-NEXT:     (block $l2 (result eqref)
 ;; CHECK-NEXT:      (br_table $l1 $l2
 ;; CHECK-NEXT:       (local.get $var)
 ;; CHECK-NEXT:       (i32.const 0)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_table-sent (param $eq eqref) (param $any anyref)
  (local $var i31ref)
  ;; Require typeof($var) <: eqref.
  (local.set $eq
   (block $l1 (result i31ref)
    ;; Require typeof($var) <: anyref.
    (local.set $any
     (block $l2 (result i31ref)
      (br_table $l1 $l2
       (local.get $var)
       (i32.const 0)
      )
     )
    )
    (unreachable)
   )
  )
 )

 ;; CHECK:      (func $br_table-sent-reversed (type $3) (param $eq eqref) (param $any anyref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (local.set $any
 ;; CHECK-NEXT:   (block $l1 (result eqref)
 ;; CHECK-NEXT:    (local.set $eq
 ;; CHECK-NEXT:     (block $l2 (result eqref)
 ;; CHECK-NEXT:      (br_table $l1 $l2
 ;; CHECK-NEXT:       (local.get $var)
 ;; CHECK-NEXT:       (i32.const 0)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_table-sent-reversed (param $eq eqref) (param $any anyref)
  ;; Same as above, but with the sources of requirements flipped.
  (local $var i31ref)
  ;; Require typeof($var) <: anyref.
  (local.set $any
   (block $l1 (result i31ref)
    ;; Require typeof($var) <: eqref.
    (local.set $eq
     (block $l2 (result i31ref)
      (br_table $l1 $l2
       (local.get $var)
       (i32.const 0)
      )
     )
    )
    (unreachable)
   )
  )
 )

 ;; CHECK:      (func $local-set (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (ref.i31
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $local-set
  ;; This will be optimized to anyref.
  (local $var i31ref)
  ;; Require that (ref i31) <: typeof($var).
  (local.set $var
   (ref.i31
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $local-get-set (type $4) (param $dest anyref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local.set $dest
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $local-get-set (param $dest anyref)
  ;; This will be optimized to anyref.
  (local $var i31ref)
  ;; Require that typeof($var) <: typeof($dest).
  (local.set $dest
   (local.get $var)
  )
 )

 ;; CHECK:      (func $local-get-set-unreachable (type $5) (param $dest i31ref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $local-get-set-unreachable (param $dest i31ref)
  ;; This is not constrained by reachable code, so we will optimize it.
  (local $var i31ref)
  (unreachable)
  ;; This would require that typeof($var) <: typeof($dest), except it is
  ;; unreachable. This would not validate if we didn't run DCE first.
  (local.set $dest
   (local.tee $var
    (local.get $var)
   )
  )
 )

 ;; CHECK:      (func $local-get-set-join (type $6) (param $dest1 anyref) (param $dest2 eqref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (local.set $dest1
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.set $dest2
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $local-get-set-join (param $dest1 anyref) (param $dest2 eqref)
  ;; This wll be optimized to eqref.
  (local $var i31ref)
  ;; Require that typeof($var) <: typeof($dest1).
  (local.set $dest1
   (local.get $var)
  )
  ;; Also require that typeof($var) <: typeof($dest2).
  (local.set $dest2
   (local.get $var)
  )
 )

 ;; CHECK:      (func $local-get-set-chain (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $a eqref)
 ;; CHECK-NEXT:  (local $b eqref)
 ;; CHECK-NEXT:  (local $c eqref)
 ;; CHECK-NEXT:  (local.set $b
 ;; CHECK-NEXT:   (local.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.set $c
 ;; CHECK-NEXT:   (local.get $b)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.get $c)
 ;; CHECK-NEXT: )
 (func $local-get-set-chain (result eqref)
  (local $a i31ref)
  (local $b i31ref)
  (local $c i31ref)
  ;; Require that typeof($a) <: typeof($b).
  (local.set $b
   (local.get $a)
  )
  ;; Require that typeof($b) <: typeof($c).
  (local.set $c
   (local.get $b)
  )
  ;; Require that typeof($c) <: eqref.
  (local.get $c)
 )

 ;; CHECK:      (func $local-get-set-chain-out-of-order (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $a eqref)
 ;; CHECK-NEXT:  (local $b eqref)
 ;; CHECK-NEXT:  (local $c eqref)
 ;; CHECK-NEXT:  (local.set $c
 ;; CHECK-NEXT:   (local.get $b)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.set $b
 ;; CHECK-NEXT:   (local.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.get $c)
 ;; CHECK-NEXT: )
 (func $local-get-set-chain-out-of-order (result eqref)
  (local $a i31ref)
  (local $b i31ref)
  (local $c i31ref)
  ;; Require that typeof($b) <: typeof($c).
  (local.set $c
   (local.get $b)
  )
  ;; Require that typeof($a) <: typeof($b). We don't know until we evaluate the
  ;; set above that this will constrain $a to eqref.
  (local.set $b
   (local.get $a)
  )
  ;; Require that typeof($c) <: eqref.
  (local.get $c)
 )

 ;; CHECK:      (func $local-tee (type $2) (param $dest eqref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (local.tee $dest
 ;; CHECK-NEXT:    (local.tee $var
 ;; CHECK-NEXT:     (ref.i31
 ;; CHECK-NEXT:      (i32.const 0)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $local-tee (param $dest eqref)
  ;; This will be optimized to eqref.
  (local $var i31ref)
  (drop
   (local.tee $dest
    (local.tee $var
     (ref.i31
      (i32.const 0)
     )
    )
   )
  )
 )

 ;; CHECK:      (func $i31-get (type $void)
 ;; CHECK-NEXT:  (local $nullable i31ref)
 ;; CHECK-NEXT:  (local $nonnullable i31ref)
 ;; CHECK-NEXT:  (local.set $nonnullable
 ;; CHECK-NEXT:   (ref.i31
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (i31.get_s
 ;; CHECK-NEXT:    (local.get $nullable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (i31.get_u
 ;; CHECK-NEXT:    (local.get $nonnullable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $i31-get
  ;; This must stay an i31ref.
  (local $nullable i31ref)
  ;; We relax this one to be nullable i31ref as well.
  (local $nonnullable (ref i31))
  ;; Initialize the non-nullable local for validation purposes.
  (local.set $nonnullable
   (ref.i31
    (i32.const 0)
   )
  )
  (drop
   ;; Require that typeof($nullable) <: i31ref.
   (i31.get_s
    (local.get $nullable)
   )
  )
  (drop
   ;; Require that typeof($nonnullable) <: i31ref.
   (i31.get_u
    (local.get $nonnullable)
   )
  )
 )

 ;; CHECK:      (func $call (type $2) (param $x eqref)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (call $call
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call (param $x eqref)
  ;; This will be optimized to eqref.
  (local $var i31ref)
  ;; Requires typeof($var) <: eqref.
  (call $call
   (local.get $var)
  )
 )

 ;; CHECK:      (func $call_indirect (type $void)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (call_indirect $func-table (type $2)
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call_indirect
  ;; This will be optimized to eqref.
  (local $var i31ref)
  ;; Requires typeof($var) <: eqref.
  (call_indirect (param eqref)
   (local.get $var)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $global-get (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local $i32 i32)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (global.get $global-eq)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.set $i32
 ;; CHECK-NEXT:   (global.get $global-i32)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $global-get
  (local $var eqref)
  (local $i32 i32)
  ;; The global type will remain unchanged and the local will be generalized.
  (local.set $var
   (global.get $global-eq)
  )
  ;; Non-reference typed globals are ok, too.
  (local.set $i32
   (global.get $global-i32)
  )
 )

 ;; CHECK:      (func $global-set (type $void)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (local $i32 i32)
 ;; CHECK-NEXT:  (global.set $global-eq
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (global.set $global-i32
 ;; CHECK-NEXT:   (local.get $i32)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $global-set
  (local $var i31ref)
  (local $i32 i32)
  ;; Requires typeof($var) <: eqref.
  (global.set $global-eq
   (local.get $var)
  )
  ;; Non-reference typed globals are ok, too.
  (global.set $global-i32
   (local.get $i32)
  )
 )

 ;; CHECK:      (func $select (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var1 eqref)
 ;; CHECK-NEXT:  (local $var2 eqref)
 ;; CHECK-NEXT:  (select (result eqref)
 ;; CHECK-NEXT:   (local.get $var1)
 ;; CHECK-NEXT:   (local.get $var2)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $select (result eqref)
  ;; Both of these will be generalized to eqref.
  (local $var1 i31ref)
  (local $var2 i31ref)
  ;; Requires typeof($var1) <: eqref and typeof($var2) <: eqref.
  (select (result i31ref)
   (local.get $var1)
   (local.get $var2)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $ref-null (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (ref.null none)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-null
  (local $var i31ref)
  ;; No constraints on $var.
  (local.set $var
   (ref.null none)
  )
 )

 ;; CHECK:      (func $ref-is-null (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (ref.is_null
 ;; CHECK-NEXT:    (local.get $var)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-is-null
  (local $var i31ref)
  (drop
   ;; No constraints on $var.
   (ref.is_null
    (local.get $var)
   )
  )
 )

 ;; CHECK:      (func $ref-func (type $void)
 ;; CHECK-NEXT:  (local $var funcref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (ref.func $ref-func)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-func
  (local $var (ref null $void))
  ;; No constraints on $var.
  (local.set $var
   (ref.func $ref-func)
  )
 )

 ;; CHECK:      (func $ref-eq (type $void)
 ;; CHECK-NEXT:  (local $var1 eqref)
 ;; CHECK-NEXT:  (local $var2 eqref)
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (ref.eq
 ;; CHECK-NEXT:    (local.get $var1)
 ;; CHECK-NEXT:    (local.get $var2)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-eq
  (local $var1 i31ref)
  (local $var2 i31ref)
  (drop
   ;; Require that typeof($var1) <: eqref and that typeof($var2) <: eqref.
   (ref.eq
    (local.get $var1)
    (local.get $var2)
   )
  )
 )

 ;; CHECK:      (func $table-get (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (table.get $eq-table
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $table-get
  (local $var eqref)
  ;; No constraints on $var.
  (local.set $var
   (table.get $eq-table
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $table-set (type $void)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (table.set $eq-table
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $table-set
  (local $var i31ref)
  ;; Require typeof($var) <: eqref.
  (table.set $eq-table
   (i32.const 0)
   (local.get $var)
  )
 )

 ;; CHECK:      (func $table-fill (type $void)
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (table.fill $eq-table
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $table-fill
  (local $var i31ref)
  ;; Require typeof($var) <: eqref.
  (table.fill $eq-table
   (i32.const 0)
   (local.get $var)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $ref-test (type $7) (result i32)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (ref.test nullref
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-test (result i32)
  (local $var i31ref)
  ;; No constraint on $var.
  (ref.test structref
   (local.get $var)
  )
 )

 ;; CHECK:      (func $ref-cast (type $void)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (ref.cast i31ref
 ;; CHECK-NEXT:    (local.get $var)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-cast
  (local $var i31ref)
  ;; No constraint on $var.
  (drop
   (ref.cast i31ref
    (local.get $var)
   )
  )
 )

 ;; CHECK:      (func $ref-cast-limited (type $1) (result eqref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (ref.cast i31ref
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-cast-limited (result eqref)
  (local $var i31ref)
  ;; No constraint on $var.
  ;; TODO: We could eliminate the cast if we did constrain $var.
  (ref.cast i31ref
   (local.get $var)
  )
 )

 ;; CHECK:      (func $ref-cast-more-limited (type $8) (result nullref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (ref.cast nullref
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-cast-more-limited (result nullref)
  (local $var i31ref)
  ;; No constraint on $var.
  (ref.cast nullref
   (local.get $var)
  )
 )

 ;; CHECK:      (func $ref-cast-lub (type $9) (result structref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (ref.cast nullref
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-cast-lub (result structref)
  (local $var i31ref)
  ;; No constraint on $var.
  (ref.cast structref
   (local.get $var)
  )
 )

 ;; CHECK:      (func $ref-as-non-null (type $10) (result (ref eq))
 ;; CHECK-NEXT:  (local $var eqref)
 ;; CHECK-NEXT:  (ref.as_non_null
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $ref-as-non-null (result (ref eq))
  (local $var i31ref)
  ;; Require that typeof($var) <: eqref.
  (ref.as_non_null
   (local.get $var)
  )
 )

 ;; CHECK:      (func $any-convert-extern-nullable (type $11) (param $x (ref noextern)) (result anyref)
 ;; CHECK-NEXT:  (local $var externref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (any.convert_extern
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $any-convert-extern-nullable (param $x (ref noextern)) (result anyref)
  (local $var (ref noextern))
  (local.set $var
   (local.get $x)
  )
  ;; Require that typeof($var) <: externref.
  (any.convert_extern
   (local.get $var)
  )
 )

 ;; CHECK:      (func $any-convert-extern-non-nullable (type $12) (param $x (ref noextern)) (result (ref any))
 ;; CHECK-NEXT:  (local $var (ref extern))
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (local.get $x)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (any.convert_extern
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $any-convert-extern-non-nullable (param $x (ref noextern)) (result (ref any))
  (local $var (ref noextern))
  (local.set $var
   (local.get $x)
  )
  ;; Require that typeof($var) <: (ref extern).
  (any.convert_extern
   (local.get $var)
  )
 )

 ;; CHECK:      (func $extern-convert-any-nullable (type $13) (result externref)
 ;; CHECK-NEXT:  (local $var anyref)
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (ref.i31
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (extern.convert_any
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $extern-convert-any-nullable (result externref)
  (local $var (ref i31))
  (local.set $var
   (ref.i31
    (i32.const 0)
   )
  )
  ;; Require that typeof($var) <: anyref.
  (extern.convert_any
   (local.get $var)
  )
 )

 ;; CHECK:      (func $extern-convert-any-non-nullable (type $14) (result (ref extern))
 ;; CHECK-NEXT:  (local $var (ref any))
 ;; CHECK-NEXT:  (local.set $var
 ;; CHECK-NEXT:   (ref.i31
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (extern.convert_any
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $extern-convert-any-non-nullable (result (ref extern))
  (local $var (ref i31))
  (local.set $var
   (ref.i31
    (i32.const 0)
   )
  )
  ;; Require that typeof($var) <: anyref.
  (extern.convert_any
   (local.get $var)
  )
 )

 ;; CHECK:      (func $helper-any_any (type $15) (param $0 anyref) (param $1 anyref)
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $helper-any_any (param anyref anyref)
  (unreachable)
 )
)

(module
 ;; CHECK:      (type $0 (func (result eqref)))

 ;; CHECK:      (type $top (sub (func (param i31ref) (result anyref))))
 (type $top (sub (func (param i31ref) (result anyref))))
 ;; CHECK:      (type $mid (sub $top (func (param eqref) (result anyref))))
 (type $mid (sub $top (func (param eqref) (result anyref))))
 ;; CHECK:      (type $bot (sub $mid (func (param eqref) (result eqref))))
 (type $bot (sub $mid (func (param eqref) (result eqref))))

 ;; CHECK:      (type $4 (func (result anyref)))

 ;; CHECK:      (func $call-ref-params-limited (type $4) (result anyref)
 ;; CHECK-NEXT:  (local $f (ref null $mid))
 ;; CHECK-NEXT:  (local $arg eqref)
 ;; CHECK-NEXT:  (call_ref $mid
 ;; CHECK-NEXT:   (local.get $arg)
 ;; CHECK-NEXT:   (local.get $f)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call-ref-params-limited (result anyref)
  (local $f (ref null $bot))
  (local $arg i31ref)
  ;; Require that typeof($f) <: $mid and that typeof($arg) <: eqref. In
  ;; principle we could generalize $f up to $top, but then we wouldn't be able
  ;; to generalize $arg at all.
  (call_ref $bot
   (local.get $arg)
   (local.get $f)
  )
 )

 ;; CHECK:      (func $call-ref-results-limited (type $0) (result eqref)
 ;; CHECK-NEXT:  (local $f (ref null $bot))
 ;; CHECK-NEXT:  (local $arg eqref)
 ;; CHECK-NEXT:  (call_ref $bot
 ;; CHECK-NEXT:   (local.get $arg)
 ;; CHECK-NEXT:   (local.get $f)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call-ref-results-limited (result eqref)
  (local $f (ref null $bot))
  (local $arg i31ref)
  ;; Require that typeof($f) <: $bot because anything better would require a
  ;; cast on the output. Also require that typeof($arg) <: eqref.
  (call_ref $bot
   (local.get $arg)
   (local.get $f)
  )
 )

 ;; CHECK:      (func $call-ref-impossible (type $0) (result eqref)
 ;; CHECK-NEXT:  (local $f nullfuncref)
 ;; CHECK-NEXT:  (local $arg anyref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable CallRef we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $arg)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $f)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call-ref-impossible (result eqref)
  (local $f nullfuncref)
  (local $arg i31ref)
  ;; Require that typeof($f) <: nullref, but do not constrain $arg because the
  ;; call_ref will not be reached.
  (call_ref $bot
   (local.get $arg)
   (local.get $f)
  )
 )
)

(module
 ;; CHECK:      (type $top (sub (func (result anyref))))
 (type $top (sub (func (result anyref))))
 (type $mid (sub $top (func (result eqref))))
 (type $bot (sub $mid (func (result i31ref))))

 ;; CHECK:      (type $1 (func (result anyref)))

 ;; CHECK:      (func $call-ref-no-limit (type $1) (result anyref)
 ;; CHECK-NEXT:  (local $f (ref null $top))
 ;; CHECK-NEXT:  (call_ref $top
 ;; CHECK-NEXT:   (local.get $f)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $call-ref-no-limit (result anyref)
  (local $f (ref null $bot))
  ;; Require that typeof($f) <: $top because that does not limit us in any way
  ;; and we cannot possibly do better.
  (call_ref $bot
   (local.get $f)
  )
 )
)

(module

 ;; CHECK:      (type $top (sub (struct (field (mut eqref)) (field eqref))))
 (type $top (sub      (struct (field (mut eqref)) (field eqref))))
 ;; CHECK:      (type $mid (sub $top (struct (field (mut eqref)) (field eqref) (field (mut eqref)))))
 (type $mid (sub $top (struct (field (mut eqref)) (field eqref)  (field (mut eqref)))))
 ;; CHECK:      (type $2 (func (result anyref)))

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

 ;; CHECK:      (type $bot (sub $mid (struct (field (mut eqref)) (field i31ref) (field (mut eqref)))))
 (type $bot (sub $mid (struct (field (mut eqref)) (field i31ref) (field (mut eqref)))))

 ;; CHECK:      (type $struct (struct (field eqref) (field anyref)))
 (type $struct (struct (field eqref) (field anyref)))

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

 ;; CHECK:      (func $struct-new (type $2) (result anyref)
 ;; CHECK-NEXT:  (local $var1 eqref)
 ;; CHECK-NEXT:  (local $var2 anyref)
 ;; CHECK-NEXT:  (struct.new $struct
 ;; CHECK-NEXT:   (local.get $var1)
 ;; CHECK-NEXT:   (local.get $var2)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-new (result anyref)
  (local $var1 i31ref)
  (local $var2 i31ref)
  ;; Require that typeof($var1) <: eqref and that typeof($var2) <: anyref.
  (struct.new $struct
   (local.get $var1)
   (local.get $var2)
  )
 )

 ;; CHECK:      (func $struct-get (type $2) (result anyref)
 ;; CHECK-NEXT:  (local $var (ref null $top))
 ;; CHECK-NEXT:  (struct.get $top 1
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-get (result anyref)
  (local $var (ref null $bot))
  ;; Require that typeof($var) <: (ref null $top) because it has a field of the
  ;; right type at index 1.
  (struct.get $bot 1
   (local.get $var)
  )
 )

 ;; CHECK:      (func $struct-get-type (type $6) (result i31ref)
 ;; CHECK-NEXT:  (local $var (ref null $bot))
 ;; CHECK-NEXT:  (struct.get $bot 1
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-get-type (result i31ref)
  (local $var (ref null $bot))
  ;; Require that typeof($var) <: (ref null $bot) because further supertypes do
  ;; not satisfy the requirement on the result type.
  (struct.get $bot 1
   (local.get $var)
  )
 )

 ;; CHECK:      (func $struct-get-index (type $2) (result anyref)
 ;; CHECK-NEXT:  (local $var (ref null $mid))
 ;; CHECK-NEXT:  (struct.get $mid 2
 ;; CHECK-NEXT:   (local.get $var)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-get-index (result anyref)
  (local $var (ref null $bot))
  ;; Require that typeof($var) <: (ref null $mid) because further supertypes do
  ;; not have a field at index 2.
  (struct.get $bot 2
   (local.get $var)
  )
 )

 ;; CHECK:      (func $struct-get-impossible (type $2) (result anyref)
 ;; CHECK-NEXT:  (local $var nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable StructGet we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $var)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-get-impossible (result anyref)
  (local $var nullref)
  (struct.get $bot 0
   (local.get $var)
  )
 )

 ;; CHECK:      (func $struct-set (type $3)
 ;; CHECK-NEXT:  (local $ref (ref null $top))
 ;; CHECK-NEXT:  (local $val eqref)
 ;; CHECK-NEXT:  (struct.set $top 0
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-set
  (local $ref (ref null $bot))
  (local $val i31ref)
  ;; Require that typeof($ref) <: (ref null $top) because it has a field at
  ;; index 0 and require that typeof($val) <: eqref because that is the type of
  ;; the field.
  (struct.set $bot 0
   (local.get $ref)
   (local.get $val)
  )
 )

 ;; CHECK:      (func $struct-set-index (type $3)
 ;; CHECK-NEXT:  (local $ref (ref null $mid))
 ;; CHECK-NEXT:  (local $val eqref)
 ;; CHECK-NEXT:  (struct.set $mid 2
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-set-index
  (local $ref (ref null $bot))
  (local $val i31ref)
  ;; Require that typeof($ref) <: (ref null $mid) because further supertypes do
  ;; not have a field at index 2 and require that typeof($val) <: eqref because
  ;; that is the type of the field.
  (struct.set $bot 2
   (local.get $ref)
   (local.get $val)
  )
 )

 ;; CHECK:      (func $struct-set-impossible (type $3)
 ;; CHECK-NEXT:  (local $ref nullref)
 ;; CHECK-NEXT:  (local $val anyref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable StructSet we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $val)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $struct-set-impossible
  (local $ref nullref)
  (local $val nullref)
  ;; Require that typeof($ref) <: nullref, but do not constrain $val.
  (struct.set $bot 0
   (local.get $ref)
   (local.get $val)
  )
 )
)

(module
 ;; CHECK:      (type $0 (func))

 ;; CHECK:      (type $super-mut (sub (array (mut eqref))))

 ;; CHECK:      (type $super (sub (array eqref)))
 (type $super (sub (array (field eqref))))
 ;; CHECK:      (type $3 (func (result anyref)))

 ;; CHECK:      (type $mut-bytes (sub (array (mut i8))))

 ;; CHECK:      (type $bytes (sub (array i8)))

 ;; CHECK:      (type $sub (sub $super (array i31ref)))
 (type $sub (sub $super (array (field i31ref))))

 (type $super-mut (sub (array (field (mut eqref)))))
 (type $sub-mut (sub $super-mut (array (field (mut eqref)))))

 (type $bytes (sub (array i8)))
 (type $sub-bytes (sub $bytes (array i8)))

 (type $mut-bytes (sub (array (mut i8))))
 (type $sub-mut-bytes (sub $mut-bytes (array (mut i8))))

 ;; CHECK:      (data $data "")

 ;; CHECK:      (elem $elem i31ref)
 (elem $elem i31ref)

 (data $data "")

 ;; CHECK:      (func $array-new (type $3) (result anyref)
 ;; CHECK-NEXT:  (local $val eqref)
 ;; CHECK-NEXT:  (array.new $super
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-new (result anyref)
  (local $val i31ref)
  ;; Require that typeof($val) <: eqref.
  (array.new $super
   (local.get $val)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-new-data (type $0)
 ;; CHECK-NEXT:  (local $val anyref)
 ;; CHECK-NEXT:  (local.set $val
 ;; CHECK-NEXT:   (array.new_data $bytes $data
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-new-data
  (local $val arrayref)
  ;; No constraint on $val.
  (local.set $val
   (array.new_data $bytes $data
    (i32.const 0)
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $array-new-elem (type $0)
 ;; CHECK-NEXT:  (local $val anyref)
 ;; CHECK-NEXT:  (local.set $val
 ;; CHECK-NEXT:   (array.new_elem $sub $elem
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-new-elem
  (local $val arrayref)
  ;; No constraint on $val.
  (local.set $val
   (array.new_elem $sub $elem
    (i32.const 0)
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $array-new-fixed (type $3) (result anyref)
 ;; CHECK-NEXT:  (local $val1 eqref)
 ;; CHECK-NEXT:  (local $val2 eqref)
 ;; CHECK-NEXT:  (array.new_fixed $super 2
 ;; CHECK-NEXT:   (local.get $val1)
 ;; CHECK-NEXT:   (local.get $val2)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-new-fixed (result anyref)
  (local $val1 i31ref)
  (local $val2 i31ref)
  ;; Require that typeof($val1) <: eqref and that typeof($val2) <: eqref.
  (array.new_fixed $super 2
   (local.get $val1)
   (local.get $val2)
  )
 )

 ;; CHECK:      (func $array-get (type $3) (result anyref)
 ;; CHECK-NEXT:  (local $val (ref null $super))
 ;; CHECK-NEXT:  (array.get $super
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-get (result anyref)
  (local $val (ref null $sub))
  ;; Require that typeof($val) <: (ref null $super).
  (array.get $sub
   (local.get $val)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-get-impossible (type $3) (result anyref)
 ;; CHECK-NEXT:  (local $val nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayGet we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $val)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-get-impossible (result anyref)
  (local $val nullref)
  ;; Require that typeof($val) <: nullref.
  (array.get $sub
   (local.get $val)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-set (type $0)
 ;; CHECK-NEXT:  (local $ref (ref null $super-mut))
 ;; CHECK-NEXT:  (local $val eqref)
 ;; CHECK-NEXT:  (array.set $super-mut
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-set
  (local $ref (ref null $sub-mut))
  (local $val i31ref)
  ;; Require that typeof($ref) <: (ref null $super-mut) and that typeof($val) <:
  ;; eqref.
  (array.set $sub-mut
   (local.get $ref)
   (i32.const 0)
   (local.get $val)
  )
 )

 ;; CHECK:      (func $array-set-impossible (type $0)
 ;; CHECK-NEXT:  (local $ref nullref)
 ;; CHECK-NEXT:  (local $val anyref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArraySet we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $val)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-set-impossible
  (local $ref nullref)
  (local $val i31ref)
  ;; Require that typeof($ref) <: nullref and do not constrain $ref.
  (array.set $sub-mut
   (local.get $ref)
   (i32.const 0)
   (local.get $val)
  )
 )

 ;; CHECK:      (func $array-len (type $0)
 ;; CHECK-NEXT:  (local $ref arrayref)
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (array.len
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-len
  (local $ref (ref null $super))
  (drop
   ;; Require that typeof($ref) <: arrayref.
   (array.len
    (local.get $ref)
   )
  )
 )

 ;; CHECK:      (func $array-copy-ref (type $0)
 ;; CHECK-NEXT:  (local $dest (ref null $super-mut))
 ;; CHECK-NEXT:  (local $src (ref null $super))
 ;; CHECK-NEXT:  (array.copy $super-mut $super
 ;; CHECK-NEXT:   (local.get $dest)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $src)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-copy-ref
  (local $dest (ref null $sub-mut))
  (local $src (ref null $sub))
  ;; Require that typeof($dest) <: $super-mut and that typeof($src) <: $super.
  (array.copy $sub-mut $sub
   (local.get $dest)
   (i32.const 0)
   (local.get $src)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-copy-i8 (type $0)
 ;; CHECK-NEXT:  (local $dest (ref null $mut-bytes))
 ;; CHECK-NEXT:  (local $src (ref null $bytes))
 ;; CHECK-NEXT:  (array.copy $mut-bytes $bytes
 ;; CHECK-NEXT:   (local.get $dest)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $src)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-copy-i8
  ;; Same as above, but now the copied element type is not a ref.
  (local $dest (ref null $sub-mut-bytes))
  (local $src (ref null $sub-bytes))
  ;; Require that typeof($dest) <: $mut-bytes and that typeof($src) <: $bytes.
  (array.copy $sub-mut-bytes $sub-bytes
   (local.get $dest)
   (i32.const 0)
   (local.get $src)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-copy-impossible-dest (type $0)
 ;; CHECK-NEXT:  (local $dest nullref)
 ;; CHECK-NEXT:  (local $src anyref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayCopy we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $dest)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $src)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-copy-impossible-dest
  ;; Same as above, but now the dest is bottom.
  (local $dest nullref)
  (local $src (ref null $sub))
  ;; Require that typeof($dest) <: nullref but do not constrain $src.
  (array.copy $sub-mut $sub
   (local.get $dest)
   (i32.const 0)
   (local.get $src)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-copy-impossible-src (type $0)
 ;; CHECK-NEXT:  (local $dest anyref)
 ;; CHECK-NEXT:  (local $src nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayCopy we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $dest)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $src)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-copy-impossible-src
  ;; Same as above, but now the src is bottom instead.
  (local $dest (ref null $sub-mut))
  (local $src nullref)
  ;; Require that typeof($src) <: nullref but do not constrain $dest.
  (array.copy $sub-mut $sub
   (local.get $dest)
   (i32.const 0)
   (local.get $src)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-copy-impossible-both (type $0)
 ;; CHECK-NEXT:  (local $dest nullref)
 ;; CHECK-NEXT:  (local $src nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayCopy we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $dest)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $src)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-copy-impossible-both
  ;; Same as above, but now both src and dest are bottom.
  (local $dest nullref)
  (local $src nullref)
  ;; Do not constrain $src or $dest.
  (array.copy $sub-mut $sub
   (local.get $dest)
   (i32.const 0)
   (local.get $src)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-fill (type $0)
 ;; CHECK-NEXT:  (local $ref (ref null $super-mut))
 ;; CHECK-NEXT:  (local $val eqref)
 ;; CHECK-NEXT:  (array.fill $super-mut
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (local.get $val)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-fill
  (local $ref (ref null $sub-mut))
  (local $val i31ref)
  ;; Require that typeof($ref) <: (ref null $super-mut) and that typeof($val) <:
  ;; eqref.
  (array.fill $sub-mut
   (local.get $ref)
   (i32.const 0)
   (local.get $val)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-fill-impossible (type $0)
 ;; CHECK-NEXT:  (local $ref nullref)
 ;; CHECK-NEXT:  (local $val anyref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayFill we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $val)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-fill-impossible
  (local $ref nullref)
  (local $val i31ref)
  ;; Require that typeof($ref) <: nullref, but do not constrain $val.
  (array.fill $sub-mut
   (local.get $ref)
   (i32.const 0)
   (local.get $val)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-init-data (type $0)
 ;; CHECK-NEXT:  (local $ref (ref null $mut-bytes))
 ;; CHECK-NEXT:  (array.init_data $mut-bytes $data
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-init-data
  (local $ref (ref null $sub-mut-bytes))
  ;; Require that typeof($ref) <: (ref null $mut-bytes).
  (array.init_data $sub-mut-bytes $data
   (local.get $ref)
   (i32.const 0)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-init-data-impossible (type $0)
 ;; CHECK-NEXT:  (local $ref nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayInitData we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-init-data-impossible
  (local $ref nullref)
  ;; Require that typeof($ref) <: nullref.
  (array.init_data $sub-mut-bytes $data
   (local.get $ref)
   (i32.const 0)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-init-elem (type $0)
 ;; CHECK-NEXT:  (local $ref (ref null $super-mut))
 ;; CHECK-NEXT:  (array.init_elem $super-mut $elem
 ;; CHECK-NEXT:   (local.get $ref)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:   (i32.const 0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-init-elem
  (local $ref (ref null $sub-mut))
  ;; Require that typeof($ref) <: (ref null $super-mut).
  (array.init_elem $sub-mut $elem
   (local.get $ref)
   (i32.const 0)
   (i32.const 0)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $array-init-elem-impossible (type $0)
 ;; CHECK-NEXT:  (local $ref nullref)
 ;; CHECK-NEXT:  (block ;; (replaces unreachable ArrayInitElem we can't emit)
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (local.get $ref)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (i32.const 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $array-init-elem-impossible
  (local $ref nullref)
  ;; Require that typeof($ref) <: nullref.
  (array.init_elem $sub-mut $elem
   (local.get $ref)
   (i32.const 0)
   (i32.const 0)
   (i32.const 0)
  )
 )
)