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

;; Test that our hack for br_if output types works with continuation types,
;; which are not castable.

;; RUN: wasm-opt %s -all --roundtrip -S -o - | filecheck %s

(module
 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $cont (cont $none))
  (type $cont (cont $none))
  ;; CHECK:       (type $none (func))
  (type $none (func))
 )

 ;; CHECK:      (func $suspend (type $none)
 ;; CHECK-NEXT:  (nop)
 ;; CHECK-NEXT: )
 (func $suspend (type $none)
  (nop)
 )

 ;; CHECK:      (func $br_if_gc (type $3) (param $ref (ref any)) (result anyref)
 ;; CHECK-NEXT:  (block $block (result anyref)
 ;; CHECK-NEXT:   (call $receive_any
 ;; CHECK-NEXT:    (ref.cast (ref any)
 ;; CHECK-NEXT:     (br_if $block
 ;; CHECK-NEXT:      (local.get $ref)
 ;; CHECK-NEXT:      (i32.const 0)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_if_gc (param $ref (ref any)) (result anyref)
  ;; After the roundtrip here we should see a cast, and no added locals.
  (block $label (result anyref)
   (call $receive_any ;; ensure the value flowing out is fully refined
    (br_if $label
     (local.get $ref)
     (i32.const 0)
    )
   )
   (unreachable)
  )
 )

 ;; CHECK:      (func $br_if_cont (type $4) (result contref)
 ;; CHECK-NEXT:  (local $0 (ref (exact $cont)))
 ;; CHECK-NEXT:  (local $1 i32)
 ;; CHECK-NEXT:  (local $scratch (ref (exact $cont)))
 ;; CHECK-NEXT:  (block $block (result contref)
 ;; CHECK-NEXT:   (local.set $0
 ;; CHECK-NEXT:    (block (result (ref (exact $cont)))
 ;; CHECK-NEXT:     (local.set $scratch
 ;; CHECK-NEXT:      (cont.new $cont
 ;; CHECK-NEXT:       (ref.func $suspend)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.set $1
 ;; CHECK-NEXT:      (i32.const 0)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $scratch)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (br_if $block
 ;; CHECK-NEXT:     (local.get $0)
 ;; CHECK-NEXT:     (local.get $1)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (call $receive_cont
 ;; CHECK-NEXT:    (local.get $0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (unreachable)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_if_cont (result contref)
  ;; After the roundtrip here we should see stashing of the continuation into a
  ;; local, rather than a cast (as continuations cannot be cast).
  (block $label (result contref)
   (call $receive_cont
    (br_if $label
     (cont.new $cont
      (ref.func $suspend)
     )
     (i32.const 0)
    )
   )
   (unreachable)
  )
 )

 ;; CHECK:      (func $receive_any (type $5) (param $0 (ref any))
 ;; CHECK-NEXT: )
 (func $receive_any (param (ref any))
 )

 ;; CHECK:      (func $receive_cont (type $6) (param $0 (ref $cont))
 ;; CHECK-NEXT: )
 (func $receive_cont (param (ref $cont))
 )

 ;; As above, but with tuples.

 ;; CHECK:      (func $br_if_gc_tuple (type $7) (param $ref (ref any)) (result anyref i32)
 ;; CHECK-NEXT:  (local $1 (ref any))
 ;; CHECK-NEXT:  (local $2 i32)
 ;; CHECK-NEXT:  (local $3 i32)
 ;; CHECK-NEXT:  (local $scratch i32)
 ;; CHECK-NEXT:  (local $scratch_5 (ref any))
 ;; CHECK-NEXT:  (local $scratch_6 (tuple (ref any) i32))
 ;; CHECK-NEXT:  (local $scratch_7 (ref any))
 ;; CHECK-NEXT:  (block $block (type $8) (result anyref i32)
 ;; CHECK-NEXT:   (local.set $1
 ;; CHECK-NEXT:    (block (result (ref any))
 ;; CHECK-NEXT:     (local.set $scratch_5
 ;; CHECK-NEXT:      (local.get $ref)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.set $3
 ;; CHECK-NEXT:      (block (result i32)
 ;; CHECK-NEXT:       (local.set $scratch
 ;; CHECK-NEXT:        (i32.const 1)
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:       (local.set $2
 ;; CHECK-NEXT:        (i32.const 0)
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:       (local.get $scratch)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $scratch_5)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (block (result (ref any))
 ;; CHECK-NEXT:     (local.set $scratch_7
 ;; CHECK-NEXT:      (tuple.extract 2 0
 ;; CHECK-NEXT:       (local.tee $scratch_6
 ;; CHECK-NEXT:        (br_if $block
 ;; CHECK-NEXT:         (tuple.make 2
 ;; CHECK-NEXT:          (local.get $1)
 ;; CHECK-NEXT:          (local.get $3)
 ;; CHECK-NEXT:         )
 ;; CHECK-NEXT:         (local.get $2)
 ;; CHECK-NEXT:        )
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (drop
 ;; CHECK-NEXT:      (tuple.extract 2 1
 ;; CHECK-NEXT:       (local.get $scratch_6)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $scratch_7)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (tuple.make 2
 ;; CHECK-NEXT:    (local.get $1)
 ;; CHECK-NEXT:    (local.get $3)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_if_gc_tuple (param $ref (ref any)) (result anyref i32)
  ;; We use locals here, avoiding casts - since we are using locals anyhow, we
  ;; don't need any casts (we stash the refined values).
  (block $label (result anyref i32)
   (br_if $label
    (tuple.make 2
     (local.get $ref)
     (i32.const 1)
    )
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $br_if_cont_tuple (type $2) (result contref i32)
 ;; CHECK-NEXT:  (local $0 (ref (exact $cont)))
 ;; CHECK-NEXT:  (local $1 i32)
 ;; CHECK-NEXT:  (local $2 i32)
 ;; CHECK-NEXT:  (local $scratch i32)
 ;; CHECK-NEXT:  (local $scratch_4 (ref (exact $cont)))
 ;; CHECK-NEXT:  (local $scratch_5 (tuple (ref (exact $cont)) i32))
 ;; CHECK-NEXT:  (local $scratch_6 (ref (exact $cont)))
 ;; CHECK-NEXT:  (block $block (type $2) (result contref i32)
 ;; CHECK-NEXT:   (local.set $0
 ;; CHECK-NEXT:    (block (result (ref (exact $cont)))
 ;; CHECK-NEXT:     (local.set $scratch_4
 ;; CHECK-NEXT:      (cont.new $cont
 ;; CHECK-NEXT:       (ref.func $suspend)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.set $2
 ;; CHECK-NEXT:      (block (result i32)
 ;; CHECK-NEXT:       (local.set $scratch
 ;; CHECK-NEXT:        (i32.const 1)
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:       (local.set $1
 ;; CHECK-NEXT:        (i32.const 0)
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:       (local.get $scratch)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $scratch_4)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (drop
 ;; CHECK-NEXT:    (block (result (ref (exact $cont)))
 ;; CHECK-NEXT:     (local.set $scratch_6
 ;; CHECK-NEXT:      (tuple.extract 2 0
 ;; CHECK-NEXT:       (local.tee $scratch_5
 ;; CHECK-NEXT:        (br_if $block
 ;; CHECK-NEXT:         (tuple.make 2
 ;; CHECK-NEXT:          (local.get $0)
 ;; CHECK-NEXT:          (local.get $2)
 ;; CHECK-NEXT:         )
 ;; CHECK-NEXT:         (local.get $1)
 ;; CHECK-NEXT:        )
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (drop
 ;; CHECK-NEXT:      (tuple.extract 2 1
 ;; CHECK-NEXT:       (local.get $scratch_5)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $scratch_6)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (tuple.make 2
 ;; CHECK-NEXT:    (local.get $0)
 ;; CHECK-NEXT:    (local.get $2)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $br_if_cont_tuple (result contref i32)
  ;; As above, locals are used (and here, casts would also be invalid).
  (block $label (result contref i32)
   (br_if $label
    (tuple.make 2
     (cont.new $cont
      (ref.func $suspend)
     )
     (i32.const 1)
    )
    (i32.const 0)
   )
  )
 )
)
