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

;; RUN: wasm-opt %s -all --optimize-instructions -S -o - | filecheck %s
;; RUN: wasm-opt %s -all --optimize-instructions -tnh -S -o - | filecheck %s --check-prefix=NTRAP

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $struct (sub (descriptor $desc) (struct)))
    ;; NTRAP:      (rec
    ;; NTRAP-NEXT:  (type $struct (sub (descriptor $desc) (struct)))
    (type $struct (sub (descriptor $desc) (struct)))
    ;; CHECK:       (type $desc (sub (describes $struct) (struct)))
    ;; NTRAP:       (type $desc (sub (describes $struct) (struct)))
    (type $desc (sub (describes $struct) (struct)))
  )

  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $sub (sub $struct (descriptor $sub.desc) (struct)))
    ;; NTRAP:      (rec
    ;; NTRAP-NEXT:  (type $sub (sub $struct (descriptor $sub.desc) (struct)))
    (type $sub (sub $struct (descriptor $sub.desc) (struct)))
    ;; CHECK:       (type $sub.desc (sub $desc (describes $sub) (struct)))
    ;; NTRAP:       (type $sub.desc (sub $desc (describes $sub) (struct)))
    (type $sub.desc (sub $desc (describes $sub) (struct)))
  )

  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $struct-i32 (descriptor $struct-i32.desc) (struct (field i32)))
    ;; NTRAP:      (rec
    ;; NTRAP-NEXT:  (type $struct-i32 (descriptor $struct-i32.desc) (struct (field i32)))
    (type $struct-i32 (descriptor $struct-i32.desc) (struct (field i32)))
    ;; CHECK:       (type $struct-i32.desc (describes $struct-i32) (struct))
    ;; NTRAP:       (type $struct-i32.desc (describes $struct-i32) (struct))
    (type $struct-i32.desc (describes $struct-i32) (struct))
  )

  ;; CHECK:      (import "" "" (func $effect (type $4)))
  ;; NTRAP:      (import "" "" (func $effect (type $4)))
  (import "" "" (func $effect))

  ;; CHECK:      (func $trap-null-desc (type $10) (result (ref (exact $struct)))
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $trap-null-desc (type $10) (result (ref (exact $struct)))
  ;; NTRAP-NEXT:  (unreachable)
  ;; NTRAP-NEXT: )
  (func $trap-null-desc (result (ref (exact $struct)))
    (struct.new_desc $struct
      (ref.null none)
    )
  )

  ;; CHECK:      (func $trap-null-desc-fallthrough (type $10) (result (ref (exact $struct)))
  ;; CHECK-NEXT:  (local $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (local.tee $desc
  ;; CHECK-NEXT:    (ref.null none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $trap-null-desc-fallthrough (type $10) (result (ref (exact $struct)))
  ;; NTRAP-NEXT:  (local $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (local.tee $desc
  ;; NTRAP-NEXT:    (ref.null none)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT:  (unreachable)
  ;; NTRAP-NEXT: )
  (func $trap-null-desc-fallthrough (result (ref (exact $struct)))
    (local $desc (ref null (exact $desc)))
    (struct.new_desc $struct
      (local.tee $desc
        (ref.null none)
      )
    )
  )

  ;; CHECK:      (func $nonnull-cast-desc-eq (type $19) (param $desc (ref null (exact $desc))) (result (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.new_default_desc $struct
  ;; CHECK-NEXT:   (local.get $desc)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $nonnull-cast-desc-eq (type $19) (param $desc (ref null (exact $desc))) (result (ref (exact $struct)))
  ;; NTRAP-NEXT:  (struct.new_default_desc $struct
  ;; NTRAP-NEXT:   (local.get $desc)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $nonnull-cast-desc-eq (param $desc (ref null (exact $desc))) (result (ref (exact $struct)))
    (struct.new_desc $struct
      (ref.as_non_null
        (local.get $desc)
      )
    )
  )

  ;; Test that when we optimize a struct.new to a struct.new_default, we drop
  ;; the field operands but keep the descriptor.
  ;; CHECK:      (func $new-default-keep-desc (type $11) (result anyref)
  ;; CHECK-NEXT:  (struct.new_default_desc $struct-i32
  ;; CHECK-NEXT:   (block (result (ref (exact $struct-i32.desc)))
  ;; CHECK-NEXT:    (call $effect)
  ;; CHECK-NEXT:    (struct.new_default $struct-i32.desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $new-default-keep-desc (type $11) (result anyref)
  ;; NTRAP-NEXT:  (struct.new_default_desc $struct-i32
  ;; NTRAP-NEXT:   (block (result (ref (exact $struct-i32.desc)))
  ;; NTRAP-NEXT:    (call $effect)
  ;; NTRAP-NEXT:    (struct.new_default $struct-i32.desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $new-default-keep-desc (result anyref)
    (struct.new_desc $struct-i32
      (i32.const 0)
      (block (result (ref (exact $struct-i32.desc)))
        ;; This would cause the descriptor to be dropped if it were dropped with
        ;; the other children.
        (call $effect)
        (struct.new_default $struct-i32.desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-null-desc (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-null-desc (type $4)
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (unreachable)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-null-desc
    (drop
      (ref.cast_desc_eq (ref (exact $struct))
        (struct.new_desc $struct
          (struct.new $desc)
        )
        (ref.null none)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-no-glb (type $9) (param $nn-sub (ref $sub)) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (local.get $nn-sub)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-no-glb (type $9) (param $nn-sub (ref $sub)) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (local.get $nn-sub)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-no-glb (param $nn-sub (ref $sub)) (param $desc (ref $desc))
    (drop
      ;; We cannot improve the cast target heap type, but we can improve the
      ;; nullability. With traps-never-happen we can optimize fully.
      (ref.cast_desc_eq (ref null $struct)
        (local.get $nn-sub)
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-improve-nullability (type $20) (param $nn-any (ref any)) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (local.get $nn-any)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-improve-nullability (type $20) (param $nn-any (ref any)) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; NTRAP-NEXT:    (local.get $nn-any)
  ;; NTRAP-NEXT:    (local.get $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-improve-nullability (param $nn-any (ref any)) (param $desc (ref $desc))
    (drop
      ;; Like above, but the ref isn't a subtype of the cast type. We can still
      ;; improve the nullability.
      (ref.cast_desc_eq (ref null $struct)
        (local.get $nn-any)
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-only-improve-nullability (type $8) (param $any anyref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (local.get $any)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-only-improve-nullability (type $8) (param $any anyref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; NTRAP-NEXT:    (local.get $any)
  ;; NTRAP-NEXT:    (local.get $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-only-improve-nullability (param $any anyref) (param $desc (ref $desc))
    (drop
      ;; Now the cast target is already non-nullable. We shouldn't make it
      ;; nullable.
      (ref.cast_desc_eq (ref $struct)
        (local.get $any)
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-unrelated-type (type $12) (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-unrelated-type (type $12) (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (unreachable)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-unrelated-type (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
    (drop
      ;; We know this cast will fail so we can optimize.
      (ref.cast_desc_eq (ref (exact $struct-i32))
        (local.get $struct)
        (local.get $desc-i32)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-unrelated-type-effects (type $12) (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result (ref $struct))
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result (ref (exact $struct-i32.desc)))
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $desc-i32)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-unrelated-type-effects (type $12) (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref $struct))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $struct)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref (exact $struct-i32.desc)))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $desc-i32)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (unreachable)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-unrelated-type-effects (param $struct (ref $struct)) (param $desc-i32 (ref (exact $struct-i32.desc)))
    (drop
      ;; As above, but now with effects we need to keep.
      (ref.cast_desc_eq (ref (exact $struct-i32))
        (block (result (ref $struct))
          (call $effect)
          (local.get $struct)
        )
        (block (result (ref (exact $struct-i32.desc)))
          (call $effect)
          (local.get $desc-i32)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-unrelated-type-nullable (type $13) (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref null $struct)
  ;; CHECK-NEXT:    (local.get $struct-i32)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-unrelated-type-nullable (type $13) (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.null none)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-unrelated-type-nullable (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
    (drop
      ;; Same as above, but now we allow nulls. We can optimize with traps-never-happen.
      (ref.cast_desc_eq (ref null $struct)
        (local.get $struct-i32)
        (local.get $desc)
      )
    )
  )

    ;; CHECK:      (func $cast-desc-eq-unrelated-type-nullable-effects (type $13) (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
    ;; CHECK-NEXT:  (drop
    ;; CHECK-NEXT:   (ref.cast_desc_eq (ref null $struct)
    ;; CHECK-NEXT:    (block (result (ref null $struct-i32))
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (local.get $struct-i32)
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:    (block (result (ref $desc))
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (local.get $desc)
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:   )
    ;; CHECK-NEXT:  )
    ;; CHECK-NEXT: )
    ;; NTRAP:      (func $cast-desc-eq-unrelated-type-nullable-effects (type $13) (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
    ;; NTRAP-NEXT:  (drop
    ;; NTRAP-NEXT:   (block (result nullref)
    ;; NTRAP-NEXT:    (drop
    ;; NTRAP-NEXT:     (block (result (ref null $struct-i32))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (local.get $struct-i32)
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (drop
    ;; NTRAP-NEXT:     (block (result (ref $desc))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (local.get $desc)
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (ref.null none)
    ;; NTRAP-NEXT:   )
    ;; NTRAP-NEXT:  )
    ;; NTRAP-NEXT: )
    (func $cast-desc-eq-unrelated-type-nullable-effects (param $struct-i32 (ref null $struct-i32)) (param $desc (ref $desc))
    (drop
      ;; Same as above, but now with effects we cannot drop.
      (ref.cast_desc_eq (ref null $struct)
        (block (result (ref null $struct-i32))
          (call $effect)
          (local.get $struct-i32)
        )
        (block (result (ref $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-wrong-desc (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
  ;; CHECK-NEXT:    (struct.new_default_desc $struct
  ;; CHECK-NEXT:     (struct.new_default $desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.new_default $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-wrong-desc (type $4)
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref (exact $struct)))
  ;; NTRAP-NEXT:    (struct.new_default_desc $struct
  ;; NTRAP-NEXT:     (struct.new_default $desc)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-wrong-desc
    (drop
      ;; With traps-never-happen we assume the cast will succeed and optimize it
      ;; out, even even though it would actually fail.
      ;; TODO: We could see that the descriptor used in the allocation and the
      ;; descriptor used in the cast are different and optimize without TNH.
      (ref.cast_desc_eq (ref (exact $struct))
        (struct.new_desc $struct
          (struct.new $desc)
        )
        (struct.new $desc)
      )
    )
  )

    ;; CHECK:      (func $cast-desc-eq-wrong-desc-effects (type $4)
    ;; CHECK-NEXT:  (drop
    ;; CHECK-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
    ;; CHECK-NEXT:    (block (result (ref (exact $struct)))
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (struct.new_default_desc $struct
    ;; CHECK-NEXT:      (struct.new_default $desc)
    ;; CHECK-NEXT:     )
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:    (block (result (ref (exact $desc)))
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (struct.new_default $desc)
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:   )
    ;; CHECK-NEXT:  )
    ;; CHECK-NEXT: )
    ;; NTRAP:      (func $cast-desc-eq-wrong-desc-effects (type $4)
    ;; NTRAP-NEXT:  (local $0 (ref (exact $struct)))
    ;; NTRAP-NEXT:  (local $1 (ref (exact $desc)))
    ;; NTRAP-NEXT:  (drop
    ;; NTRAP-NEXT:   (block (result (ref (exact $struct)))
    ;; NTRAP-NEXT:    (local.set $0
    ;; NTRAP-NEXT:     (block (result (ref (exact $struct)))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (struct.new_default_desc $struct
    ;; NTRAP-NEXT:       (struct.new_default $desc)
    ;; NTRAP-NEXT:      )
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (local.set $1
    ;; NTRAP-NEXT:     (block (result (ref (exact $desc)))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (struct.new_default $desc)
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (local.get $0)
    ;; NTRAP-NEXT:   )
    ;; NTRAP-NEXT:  )
    ;; NTRAP-NEXT: )
    (func $cast-desc-eq-wrong-desc-effects
    (drop
      ;; Same, but with effects.
      (ref.cast_desc_eq (ref (exact $struct))
        (block (result (ref (exact $struct)))
          (call $effect)
          (struct.new_desc $struct
            (struct.new $desc)
          )
        )
        (block (result (ref (exact $desc)))
          (call $effect)
          (struct.new $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-weaker-nondesc-child (type $14) (param $ref anyref) (param $desc (ref $sub.desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; CHECK-NEXT:    (local.get $ref)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-weaker-nondesc-child (type $14) (param $ref anyref) (param $desc (ref $sub.desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; NTRAP-NEXT:    (local.get $ref)
  ;; NTRAP-NEXT:    (local.get $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-weaker-nondesc-child (param $ref anyref) (param $desc (ref $sub.desc))
    (drop
      ;; Optimize out the weaker child cast.
      (ref.cast_desc_eq (ref $sub)
        (ref.cast (ref any)
          (local.get $ref)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-weaker-nondesc-child-effects (type $14) (param $ref anyref) (param $desc (ref $sub.desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (block (result anyref)
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (block (result (ref $sub.desc))
  ;; CHECK-NEXT:     (call $effect)
  ;; CHECK-NEXT:     (local.get $desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-weaker-nondesc-child-effects (type $14) (param $ref anyref) (param $desc (ref $sub.desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; NTRAP-NEXT:    (ref.as_non_null
  ;; NTRAP-NEXT:     (block (result anyref)
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $ref)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (block (result (ref $sub.desc))
  ;; NTRAP-NEXT:     (call $effect)
  ;; NTRAP-NEXT:     (local.get $desc)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-weaker-nondesc-child-effects (param $ref anyref) (param $desc (ref $sub.desc))
    (drop
      ;; Same, but with effects. Due to ordering, we cannot remove the inner
      ;; cast (which turns into ref.as_non_null).
      (ref.cast_desc_eq (ref $sub)
        (ref.cast (ref any)
          (block (result anyref)
            (call $effect)
            (local.get $ref)
          )
        )
        (block (result (ref $sub.desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-nondesc-child (type $8) (param $ref anyref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (ref.cast (ref $sub)
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-nondesc-child (type $8) (param $ref anyref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (ref.cast (ref $sub)
  ;; NTRAP-NEXT:     (local.get $ref)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-nondesc-child (param $ref anyref) (param $desc (ref $desc))
    (drop
      ;; With traps-never-happen we assume the outer cast will succeed and
      ;; optimize it out.
      (ref.cast_desc_eq (ref $struct)
        (ref.cast (ref $sub)
          (local.get $ref)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-nondesc-child-effects (type $8) (param $ref anyref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (ref.cast (ref $sub)
  ;; CHECK-NEXT:     (block (result anyref)
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (block (result (ref $desc))
  ;; CHECK-NEXT:     (call $effect)
  ;; CHECK-NEXT:     (local.get $desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-nondesc-child-effects (type $8) (param $ref anyref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (local $2 (ref $sub))
  ;; NTRAP-NEXT:  (local $3 (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (local.set $2
  ;; NTRAP-NEXT:     (ref.cast (ref $sub)
  ;; NTRAP-NEXT:      (block (result anyref)
  ;; NTRAP-NEXT:       (call $effect)
  ;; NTRAP-NEXT:       (local.get $ref)
  ;; NTRAP-NEXT:      )
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.set $3
  ;; NTRAP-NEXT:     (block (result (ref $desc))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.get $2)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-nondesc-child-effects (param $ref anyref) (param $desc (ref $desc))
    (drop
      ;; Same, but with effects.
      (ref.cast_desc_eq (ref $struct)
        (ref.cast (ref $sub)
          (block (result anyref)
            (call $effect)
            (local.get $ref)
          )
        )
        (block (result (ref $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-weaker-desc-child (type $15) (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; CHECK-NEXT:    (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (local.get $desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $sub.desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-weaker-desc-child (type $15) (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $sub)
  ;; NTRAP-NEXT:    (block (result anyref)
  ;; NTRAP-NEXT:     (local.get $ref)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.get $sub.desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-weaker-desc-child (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
    (drop
      ;; We can only optimize the weaker child cast with traps-never-happen
      ;; because it might fail due to an incorrect descriptor even when the
      ;; parent cast would succeed.
      (ref.cast_desc_eq (ref $sub)
        (ref.cast_desc_eq (ref $struct)
          (local.get $ref)
          (local.get $desc)
        )
        (local.get $sub.desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-desc-child (type $15) (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (ref.cast_desc_eq (ref $sub)
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (local.get $sub.desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-desc-child (type $15) (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (ref.cast_desc_eq (ref $sub)
  ;; NTRAP-NEXT:     (local.get $ref)
  ;; NTRAP-NEXT:     (local.get $sub.desc)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-desc-child (param $ref anyref) (param $desc (ref $desc)) (param $sub.desc (ref $sub.desc))
    (drop
      ;; Like above, but now when we optimize with traps-never-happen we replace
      ;; the parent with the child.
      (ref.cast_desc_eq (ref $struct)
        (ref.cast_desc_eq (ref $sub)
          (local.get $ref)
          (local.get $sub.desc)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough (type $9) (param $sub (ref $sub)) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (block (result anyref)
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough (type $9) (param $sub (ref $sub)) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (local $2 (ref $sub))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref $sub))
  ;; NTRAP-NEXT:      (local.tee $2
  ;; NTRAP-NEXT:       (local.get $sub)
  ;; NTRAP-NEXT:      )
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.get $2)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough (param $sub (ref $sub)) (param $desc (ref $desc))
    (drop
      ;; Like above, but now the stronger child is deeper. We use a tee to
      ;; extract it.
      (ref.cast_desc_eq (ref $struct)
        (block (result anyref)
          (local.get $sub)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-effects (type $9) (param $sub (ref $sub)) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (block (result anyref)
  ;; CHECK-NEXT:     (call $effect)
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (block (result (ref $desc))
  ;; CHECK-NEXT:     (call $effect)
  ;; CHECK-NEXT:     (local.get $desc)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-effects (type $9) (param $sub (ref $sub)) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (local $2 (ref $sub))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $sub))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref $sub))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.tee $2
  ;; NTRAP-NEXT:       (local.get $sub)
  ;; NTRAP-NEXT:      )
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref $desc))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.get $2)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough-effects (param $sub (ref $sub)) (param $desc (ref $desc))
    (drop
      ;; Like above, but now with effects we cannot drop.
      (ref.cast_desc_eq (ref $struct)
        (block (result anyref)
          (call $effect)
          (local.get $sub)
        )
        (block (result (ref $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

   ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-nullck (type $16) (param $sub (ref null $sub)) (param $desc (ref $desc))
   ;; CHECK-NEXT:  (drop
   ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
   ;; CHECK-NEXT:    (block (result anyref)
   ;; CHECK-NEXT:     (local.get $sub)
   ;; CHECK-NEXT:    )
   ;; CHECK-NEXT:    (local.get $desc)
   ;; CHECK-NEXT:   )
   ;; CHECK-NEXT:  )
   ;; CHECK-NEXT: )
   ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-nullck (type $16) (param $sub (ref null $sub)) (param $desc (ref $desc))
   ;; NTRAP-NEXT:  (local $2 (ref null $sub))
   ;; NTRAP-NEXT:  (drop
   ;; NTRAP-NEXT:   (block (result (ref $sub))
   ;; NTRAP-NEXT:    (drop
   ;; NTRAP-NEXT:     (block (result (ref null $sub))
   ;; NTRAP-NEXT:      (local.tee $2
   ;; NTRAP-NEXT:       (local.get $sub)
   ;; NTRAP-NEXT:      )
   ;; NTRAP-NEXT:     )
   ;; NTRAP-NEXT:    )
   ;; NTRAP-NEXT:    (ref.as_non_null
   ;; NTRAP-NEXT:     (local.get $2)
   ;; NTRAP-NEXT:    )
   ;; NTRAP-NEXT:   )
   ;; NTRAP-NEXT:  )
   ;; NTRAP-NEXT: )
   (func $cast-desc-eq-stronger-fallthrough-nullck (param $sub (ref null $sub)) (param $desc (ref $desc))
    (drop
      ;; Like above, but now we also need a null check.
      (ref.cast_desc_eq (ref $struct)
        (block (result anyref)
          (local.get $sub)
        )
        (local.get $desc)
      )
    )
  )

    ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-nullck-effects (type $16) (param $sub (ref null $sub)) (param $desc (ref $desc))
    ;; CHECK-NEXT:  (drop
    ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
    ;; CHECK-NEXT:    (block (result anyref)
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (local.get $sub)
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:    (block (result (ref $desc))
    ;; CHECK-NEXT:     (call $effect)
    ;; CHECK-NEXT:     (local.get $desc)
    ;; CHECK-NEXT:    )
    ;; CHECK-NEXT:   )
    ;; CHECK-NEXT:  )
    ;; CHECK-NEXT: )
    ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-nullck-effects (type $16) (param $sub (ref null $sub)) (param $desc (ref $desc))
    ;; NTRAP-NEXT:  (local $2 (ref null $sub))
    ;; NTRAP-NEXT:  (drop
    ;; NTRAP-NEXT:   (block (result (ref $sub))
    ;; NTRAP-NEXT:    (drop
    ;; NTRAP-NEXT:     (block (result (ref null $sub))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (local.tee $2
    ;; NTRAP-NEXT:       (local.get $sub)
    ;; NTRAP-NEXT:      )
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (drop
    ;; NTRAP-NEXT:     (block (result (ref $desc))
    ;; NTRAP-NEXT:      (call $effect)
    ;; NTRAP-NEXT:      (local.get $desc)
    ;; NTRAP-NEXT:     )
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:    (ref.as_non_null
    ;; NTRAP-NEXT:     (local.get $2)
    ;; NTRAP-NEXT:    )
    ;; NTRAP-NEXT:   )
    ;; NTRAP-NEXT:  )
    ;; NTRAP-NEXT: )
    (func $cast-desc-eq-stronger-fallthrough-nullck-effects (param $sub (ref null $sub)) (param $desc (ref $desc))
    (drop
      ;; Like above, but now with effects.
      (ref.cast_desc_eq (ref $struct)
        (block (result anyref)
          (call $effect)
          (local.get $sub)
        )
        (block (result (ref $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-null (type $17) (param $null nullref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.null none)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-null (type $17) (param $null nullref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.null none)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough-null (param $null nullref) (param $desc (ref $desc))
    (drop
      ;; Like above, but now the value itself is null and we allow it.
      (ref.cast_desc_eq (ref null $struct)
        (block (result anyref)
          (local.get $null)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-null-effects (type $17) (param $null nullref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result nullref)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result nullref)
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $null)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result (ref $desc))
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $desc)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (ref.null none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-null-effects (type $17) (param $null nullref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result nullref)
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result nullref)
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $null)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref $desc))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (ref.null none)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough-null-effects (param $null nullref) (param $desc (ref $desc))
    (drop
      ;; Like above, but now with effects.
      (ref.cast_desc_eq (ref null $struct)
        (block (result anyref)
          (call $effect)
          (local.get $null)
        )
        (block (result (ref $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-null-null-desc (type $18) (param $null nullref) (param $desc (ref null $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result nullref)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $desc)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (ref.null none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-null-null-desc (type $18) (param $null nullref) (param $desc (ref null $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.null none)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough-null-null-desc (param $null nullref) (param $desc (ref null $desc))
    (drop
      ;; Like above, but now the descriptor is nullable so we have to add a null
      ;; check to it.
      (ref.cast_desc_eq (ref null $struct)
        (block (result anyref)
          (local.get $null)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-stronger-fallthrough-null-null-desc-effects (type $18) (param $null nullref) (param $desc (ref null $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result nullref)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result nullref)
  ;; CHECK-NEXT:      (call $effect)
  ;; CHECK-NEXT:      (local.get $null)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (block (result (ref null $desc))
  ;; CHECK-NEXT:       (call $effect)
  ;; CHECK-NEXT:       (local.get $desc)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (ref.null none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-stronger-fallthrough-null-null-desc-effects (type $18) (param $null nullref) (param $desc (ref null $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result nullref)
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result nullref)
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $null)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block (result (ref null $desc))
  ;; NTRAP-NEXT:      (call $effect)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (ref.null none)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-stronger-fallthrough-null-null-desc-effects (param $null nullref) (param $desc (ref null $desc))
    (drop
      ;; Like above, but now with effects.
      (ref.cast_desc_eq (ref null $struct)
        (block (result anyref)
          (call $effect)
          (local.get $null)
        )
        (block (result (ref null $desc))
          (call $effect)
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-ref-as-non-null (type $8) (param $any anyref) (param $desc (ref $desc))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (local.get $any)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-ref-as-non-null (type $8) (param $any anyref) (param $desc (ref $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; NTRAP-NEXT:    (local.get $any)
  ;; NTRAP-NEXT:    (local.get $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-ref-as-non-null (param $any anyref) (param $desc (ref $desc))
    (drop
      ;; We can roll the ref.as_non_null into the cast.
      (ref.cast_desc_eq (ref null $struct)
        (ref.as_non_null
          (local.get $any)
        )
        (local.get $desc)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-unreachable-desc (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block ;; (replaces unreachable RefCast we can't emit)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.null none)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-unreachable-desc (type $4)
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block ;; (replaces unreachable RefCast we can't emit)
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (ref.null none)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (unreachable)
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (unreachable)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-unreachable-desc
    (drop
      ;; Don't crash on an unreachable descriptor.
      (ref.cast_desc_eq (ref $struct)
        (ref.null none)
        (unreachable)
      )
    )
  )

  ;; CHECK:      (func $ref.get_desc-skip-non-null (type $21) (param $ref (ref null $struct)) (result anyref)
  ;; CHECK-NEXT:  (ref.get_desc $struct
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $ref.get_desc-skip-non-null (type $21) (param $ref (ref null $struct)) (result anyref)
  ;; NTRAP-NEXT:  (ref.get_desc $struct
  ;; NTRAP-NEXT:   (local.get $ref)
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $ref.get_desc-skip-non-null (param $ref (ref null $struct)) (result anyref)
    (ref.get_desc $struct
      ;; This is not needed, as the parent traps on null anyhow.
      (ref.as_non_null
        (local.get $ref)
      )
    )
  )

  ;; CHECK:      (func $ref.get_desc-trap-on-null (type $11) (result anyref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $ref.get_desc-trap-on-null (type $11) (result anyref)
  ;; NTRAP-NEXT:  (unreachable)
  ;; NTRAP-NEXT: )
  (func $ref.get_desc-trap-on-null (result anyref)
    ;; This traps.
    (ref.get_desc $struct
      (block (result (ref null $struct))
        (ref.null $struct)
      )
    )
  )

  ;; CHECK:      (func $cast-desc-eq-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
  ;; CHECK-NEXT:    (local.get $ref)
  ;; CHECK-NEXT:    (local.get $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $cast-desc-eq-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
  ;; NTRAP-NEXT:    (local.get $ref)
  ;; NTRAP-NEXT:    (local.get $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $cast-desc-eq-skip-non-null (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
    (drop
      (ref.cast_desc_eq (ref (exact $struct))
        (local.get $ref)
        ;; This is not needed, as the parent traps on null anyhow.
        (ref.as_non_null
          (local.get $desc)
        )
      )
    )
  )

  ;; CHECK:      (func $br_on_cast_desc_eq-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $l (result (ref null $struct))
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (br_on_cast_desc_eq $l (ref null $struct) (ref null (exact $struct))
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:      (local.get $desc)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $br_on_cast_desc_eq-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block $l (result (ref null $struct))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (br_on_cast_desc_eq $l (ref null $struct) (ref null (exact $struct))
  ;; NTRAP-NEXT:      (local.get $ref)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (return)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $br_on_cast_desc_eq-skip-non-null (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
    (drop
      (block $l (result (ref null $struct))
        (br_on_cast_desc_eq $l anyref (ref null $struct)
          (local.get $ref)
          ;; This is not needed, as the parent traps on null anyhow.
          (ref.as_non_null
            (local.get $desc)
          )
        )
        (return)
      )
    )
  )

  ;; CHECK:      (func $br_on_cast_desc_eq_fail-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $l (result (ref null $struct))
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (br_on_cast_desc_eq_fail $l (ref null $struct) (ref null (exact $struct))
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:      (local.get $desc)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $br_on_cast_desc_eq_fail-skip-non-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block $l (result (ref null $struct))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (br_on_cast_desc_eq_fail $l (ref null $struct) (ref null (exact $struct))
  ;; NTRAP-NEXT:      (local.get $ref)
  ;; NTRAP-NEXT:      (local.get $desc)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (return)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $br_on_cast_desc_eq_fail-skip-non-null (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
    (drop
      (block $l (result (ref null $struct))
        (br_on_cast_desc_eq_fail $l anyref (ref null $struct)
          (local.get $ref)
          ;; This is not needed, as the parent traps on null anyhow.
          (ref.as_non_null
            (local.get $desc)
          )
        )
        (return)
      )
    )
  )

  ;; CHECK:      (func $br_on_cast_desc_eq-trap-on-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $l (result (ref none))
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (block ;; (replaces unreachable BrOn we can't emit)
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (local.get $ref)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (block (result nullref)
  ;; CHECK-NEXT:          (ref.null none)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (unreachable)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $br_on_cast_desc_eq-trap-on-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block $l (result (ref none))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block
  ;; NTRAP-NEXT:      (drop
  ;; NTRAP-NEXT:       (block ;; (replaces unreachable BrOn we can't emit)
  ;; NTRAP-NEXT:        (drop
  ;; NTRAP-NEXT:         (local.get $ref)
  ;; NTRAP-NEXT:        )
  ;; NTRAP-NEXT:        (drop
  ;; NTRAP-NEXT:         (block (result nullref)
  ;; NTRAP-NEXT:          (ref.null none)
  ;; NTRAP-NEXT:         )
  ;; NTRAP-NEXT:        )
  ;; NTRAP-NEXT:        (unreachable)
  ;; NTRAP-NEXT:       )
  ;; NTRAP-NEXT:      )
  ;; NTRAP-NEXT:      (unreachable)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (return)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $br_on_cast_desc_eq-trap-on-null (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
    (drop
      (block $l (result (ref null $struct))
        (br_on_cast_desc_eq $l anyref (ref null $struct)
          (local.get $ref)
          (block (result (ref null $desc))
            (ref.null $desc)
          )
        )
        (return)
      )
    )
  )

  ;; CHECK:      (func $br_on_cast_desc_eq_fail-trap-on-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $l (result (ref null $struct))
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (block ;; (replaces unreachable BrOn we can't emit)
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (local.get $ref)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (block (result nullref)
  ;; CHECK-NEXT:          (ref.null none)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (unreachable)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $br_on_cast_desc_eq_fail-trap-on-null (type $7) (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block $l (result (ref null $struct))
  ;; NTRAP-NEXT:    (drop
  ;; NTRAP-NEXT:     (block
  ;; NTRAP-NEXT:      (drop
  ;; NTRAP-NEXT:       (block ;; (replaces unreachable BrOn we can't emit)
  ;; NTRAP-NEXT:        (drop
  ;; NTRAP-NEXT:         (local.get $ref)
  ;; NTRAP-NEXT:        )
  ;; NTRAP-NEXT:        (drop
  ;; NTRAP-NEXT:         (block (result nullref)
  ;; NTRAP-NEXT:          (ref.null none)
  ;; NTRAP-NEXT:         )
  ;; NTRAP-NEXT:        )
  ;; NTRAP-NEXT:        (unreachable)
  ;; NTRAP-NEXT:       )
  ;; NTRAP-NEXT:      )
  ;; NTRAP-NEXT:      (unreachable)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (return)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $br_on_cast_desc_eq_fail-trap-on-null (param $ref (ref null $struct)) (param $desc (ref null (exact $desc)))
    (drop
      (block $l (result (ref null $struct))
        (br_on_cast_desc_eq_fail $l anyref (ref null $struct)
          (local.get $ref)
          (block (result (ref null $desc))
            (ref.null $desc)
          )
        )
        (return)
      )
    )
  )

  ;; CHECK:      (func $ref.cast_desc_eq-ref.as_non_null (type $4)
  ;; CHECK-NEXT:  (local $null (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref $struct)
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $null)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (block (result (ref null $desc))
  ;; CHECK-NEXT:     (return)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
  ;; CHECK-NEXT:    (local.get $null)
  ;; CHECK-NEXT:    (struct.new_default $desc)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NTRAP:      (func $ref.cast_desc_eq-ref.as_non_null (type $4)
  ;; NTRAP-NEXT:  (local $null (ref null $struct))
  ;; NTRAP-NEXT:  (local $1 (ref $struct))
  ;; NTRAP-NEXT:  (local $2 (ref null $desc))
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (block (result (ref $struct))
  ;; NTRAP-NEXT:    (local.set $1
  ;; NTRAP-NEXT:     (ref.as_non_null
  ;; NTRAP-NEXT:      (local.get $null)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.set $2
  ;; NTRAP-NEXT:     (block (result (ref null $desc))
  ;; NTRAP-NEXT:      (return)
  ;; NTRAP-NEXT:     )
  ;; NTRAP-NEXT:    )
  ;; NTRAP-NEXT:    (local.get $1)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT:  (drop
  ;; NTRAP-NEXT:   (ref.cast_desc_eq (ref (exact $struct))
  ;; NTRAP-NEXT:    (local.get $null)
  ;; NTRAP-NEXT:    (struct.new_default $desc)
  ;; NTRAP-NEXT:   )
  ;; NTRAP-NEXT:  )
  ;; NTRAP-NEXT: )
  (func $ref.cast_desc_eq-ref.as_non_null
    (local $null (ref null $struct))
    ;; We read a null local and cast it to non-null, trapping. The ref.cast_desc_eq
    ;; would trap on null anyhow, so it seems we can remove the ref.as_non_null,
    ;; but doing so would allow us to reach the block, which returns *before* the
    ;; ref.cast_desc_eq would trap.
    (drop
      (ref.cast_desc_eq (ref $struct)
        (ref.as_non_null
          (local.get $null)
        )
        ;; Hide the return in a block, otherwise we'd skip unreachable code.
        (block (result (ref null $desc))
          (return)
        )
      )
    )
    ;; As above, but without dangerous effects: we can remove the
    ;; ref.as_non_null.
    (drop
      (ref.cast_desc_eq (ref $struct)
        (ref.as_non_null
          (local.get $null)
        )
        (struct.new $desc)
      )
    )
  )
)
