;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s -all --merge-blocks -all -S -o - | filecheck %s

(module
  ;; CHECK:      (import "a" "b" (func $import (type $0)))
  (import "a" "b" (func $import))

  ;; CHECK:      (tag $empty)
  (tag $empty)

  ;; CHECK:      (tag $i32 (param i32))
  (tag $i32 (param i32))

  ;; CHECK:      (tag $exnref (param exnref))
  (tag $exnref (param exnref))

  ;; CHECK:      (func $drop-block-try_catch_all_ref (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (call $import)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_all_ref
    ;; This block is dropped, so the try_table's exnref value can be removed
    ;; by replacing catch_all_ref with catch_all.
    (drop
      (block $catch (result exnref)
        (try_table (catch_all_ref $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_ref (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch $empty $catch)
  ;; CHECK-NEXT:    (call $import)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_ref
    ;; As above, but with catch_ref instead of catch_all_ref. We can still
    ;; optimize.
    (drop
      (block $catch (result exnref)
        (try_table (catch_ref $empty $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_multi (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch $empty $catch) (catch_all $catch)
  ;; CHECK-NEXT:    (call $import)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_multi
    ;; As above, but with two catches, both of whom can be optimized.
    (drop
      (block $catch (result exnref)
        (try_table (catch_ref $empty $catch) (catch_all_ref $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_all_i32 (type $0)
  ;; CHECK-NEXT:  (tuple.drop 2
  ;; CHECK-NEXT:   (block $catch (type $1) (result i32 exnref)
  ;; CHECK-NEXT:    (try_table (catch_ref $i32 $catch)
  ;; CHECK-NEXT:     (call $import)
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_all_i32
    ;; Send a tag value + exnref. We don't handle this yet TODO
    (tuple.drop 2
      (block $catch (result i32 exnref)
        (try_table (catch_ref $i32 $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_multi_partial (type $0)
  ;; CHECK-NEXT:  (tuple.drop 2
  ;; CHECK-NEXT:   (block $outer (type $2) (result i32 (ref exn))
  ;; CHECK-NEXT:    (block $inner
  ;; CHECK-NEXT:     (try_table (catch_ref $i32 $outer) (catch_all $inner)
  ;; CHECK-NEXT:      (call $import)
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_multi_partial
    ;; Two catches, one of which we can optimize, but not both.
    (tuple.drop 2
      (block $outer (result i32 exnref)
        (drop
          (block $inner (result exnref)
            (try_table (catch_ref $i32 $outer) (catch_all_ref $inner)
              (call $import)
              (unreachable)
            )
          )
        )
        (unreachable)
      )
    )
  )

  ;; CHECK:      (func $drop-block_try_catch_multi-fail (type $0)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $catch (result exnref)
  ;; CHECK-NEXT:    (try_table (catch $exnref $catch) (catch_all_ref $catch)
  ;; CHECK-NEXT:     (call $import)
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block_try_catch_multi-fail
    (drop
      ;; This block is sent an exnref in two ways: once as the contents of a tag
      ;; and once as the ref of a catch_all_ref. We can remove the latter but
      ;; not the former, and they go to the same block, so we cannot optimize.
      (block $catch (result exnref)
        (try_table (catch $exnref $catch) (catch_all_ref $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_all (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (call $import)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_all
    ;; Without _ref, there is nothing to optimize (and we should not error).
    ;; Also since there is no ref, there is no drop anyhow.
    (block $catch
      (try_table (catch_all $catch)
        (call $import)
        (unreachable)
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch $empty $catch)
  ;; CHECK-NEXT:    (call $import)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch
    ;; As above, but with a catch instead of catch_all.
    (block $catch
      (try_table (catch $empty $catch)
        (call $import)
        (unreachable)
      )
    )
  )

  ;; CHECK:      (func $drop-block-try_catch_i32 (type $0)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $catch (result i32)
  ;; CHECK-NEXT:    (try_table (catch $i32 $catch)
  ;; CHECK-NEXT:     (call $import)
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $drop-block-try_catch_i32
    ;; Send an i32 without a ref. We can't optimize here, as we can't prevent
    ;; the i32 from being sent.
    (drop
      (block $catch (result i32)
        (try_table (catch $i32 $catch)
          (call $import)
          (unreachable)
        )
      )
    )
  )
)