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

;; Fairly comprehensive test case

(module
 ;; CHECK:      (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq))))
 (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq))))
 ;; CHECK:      (type $closure (sub (struct (field (ref $function_1)))))
 (type $closure (sub (struct (field (ref $function_1)))))
 ;; CHECK:      (type $cont (cont $function_1))

 ;; CHECK:      (type $function_2 (func (param (ref eq) (ref eq) (ref eq)) (result (ref eq))))
 (type $function_2 (func (param (ref eq) (ref eq) (ref eq)) (result (ref eq))))
 ;; CHECK:      (type $closure_2 (struct (field (ref $function_2))))
 (type $closure_2 (struct (field (ref $function_2))))
 ;; CHECK:      (type $handlers (struct (field $value (ref $closure)) (field $exn (ref $closure)) (field $effect (ref $closure_2))))
 (type $handlers (struct (field $value (ref $closure)) (field $exn (ref $closure)) (field $effect (ref $closure_2))))
 (type $cont (cont $function_1))
 ;; CHECK:      (type $fiber (struct (field $handlers (ref $handlers)) (field $cont (ref $cont))))
 (type $fiber (struct (field $handlers (ref $handlers)) (field $cont (ref $cont))))
 ;; CHECK:      (tag $exception (type $7) (param (ref eq)))
 (tag $exception (param (ref eq)))
 ;; CHECK:      (tag $effect (type $8) (param (ref eq)) (result (ref eq) (ref eq)))
 (tag $effect (param (ref eq)) (result (ref eq) (ref eq)))

 ;; CHECK:      (func $resume (type $9) (param $0 (ref $fiber)) (param $1 (ref $closure)) (param $2 (ref eq)) (result (ref eq))
 ;; CHECK-NEXT:  (local $3 (tuple (ref eq) (ref $cont)))
 ;; CHECK-NEXT:  (local $4 (ref $handlers))
 ;; CHECK-NEXT:  (local $5 (ref $closure_2))
 ;; CHECK-NEXT:  (return_call_ref $function_1
 ;; CHECK-NEXT:   (block $handle_exception (result (ref eq))
 ;; CHECK-NEXT:    (return_call_ref $function_2
 ;; CHECK-NEXT:     (tuple.extract 2 0
 ;; CHECK-NEXT:      (local.tee $3
 ;; CHECK-NEXT:       (block $handle_effect (type $10) (result (ref eq) (ref $cont))
 ;; CHECK-NEXT:        (return_call_ref $function_1
 ;; CHECK-NEXT:         (try_table (result (ref eq)) (catch $exception $handle_exception)
 ;; CHECK-NEXT:          (resume $cont (on $effect $handle_effect)
 ;; CHECK-NEXT:           (local.get $1)
 ;; CHECK-NEXT:           (local.get $2)
 ;; CHECK-NEXT:           (struct.get $fiber $cont
 ;; CHECK-NEXT:            (local.get $0)
 ;; CHECK-NEXT:           )
 ;; CHECK-NEXT:          )
 ;; CHECK-NEXT:         )
 ;; CHECK-NEXT:         (local.tee $1
 ;; CHECK-NEXT:          (struct.get $handlers $value
 ;; CHECK-NEXT:           (struct.get $fiber $handlers
 ;; CHECK-NEXT:            (local.get $0)
 ;; CHECK-NEXT:           )
 ;; CHECK-NEXT:          )
 ;; CHECK-NEXT:         )
 ;; CHECK-NEXT:         (struct.get $closure 0
 ;; CHECK-NEXT:          (local.get $1)
 ;; CHECK-NEXT:         )
 ;; CHECK-NEXT:        )
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (struct.new $fiber
 ;; CHECK-NEXT:      (local.tee $4
 ;; CHECK-NEXT:       (struct.get $fiber $handlers
 ;; CHECK-NEXT:        (local.get $0)
 ;; CHECK-NEXT:       )
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:      (tuple.extract 2 1
 ;; CHECK-NEXT:       (local.get $3)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.tee $5
 ;; CHECK-NEXT:      (struct.get $handlers $effect
 ;; CHECK-NEXT:       (local.get $4)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (struct.get $closure_2 0
 ;; CHECK-NEXT:      (local.get $5)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (local.tee $1
 ;; CHECK-NEXT:    (struct.get $handlers $exn
 ;; CHECK-NEXT:     (struct.get $fiber $handlers
 ;; CHECK-NEXT:      (local.get $0)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (struct.get $closure 0
 ;; CHECK-NEXT:    (local.get $1)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $resume (export "resume") (param $fiber (ref $fiber)) (param $f (ref $closure)) (param $v (ref eq)) (result (ref eq))
  (local $g (ref $closure_2))
  (local $res (ref eq))
  (local $exn (ref eq))
  (local $resume_res (tuple (ref eq) (ref $cont)))
  (local.set $exn
   (block $handle_exception (result (ref eq))
    (local.set $resume_res
     (block $handle_effect (result (ref eq) (ref $cont))
      (local.set $res
       (try_table (result (ref eq)) (catch $exception $handle_exception)
        (resume $cont (on $effect $handle_effect)
         (local.get $f)
         (local.get $v)
         (struct.get $fiber $cont
          (local.get $fiber)
         )
        )
       )
      )
      (return_call_ref $function_1
       (local.get $res)
       (local.tee $f
        (struct.get $handlers $value
         (struct.get $fiber $handlers
          (local.get $fiber)
         )
        )
       )
       (struct.get $closure 0
        (local.get $f)
       )
      )
     )
    )
    (return_call_ref $function_2
     (tuple.extract 2 0
      (local.get $resume_res)
     )
     (struct.new $fiber
      (struct.get $fiber $handlers
       (local.get $fiber)
      )
      (tuple.extract 2 1
       (local.get $resume_res)
      )
     )
     (local.tee $g
      (struct.get $handlers $effect
       (struct.get $fiber $handlers
        (local.get $fiber)
       )
      )
     )
     (struct.get $closure_2 0
      (local.get $g)
     )
    )
   )
  )
  (return_call_ref $function_1
   (local.get $exn)
   (local.tee $f
    (struct.get $handlers $exn
     (struct.get $fiber $handlers
      (local.get $fiber)
     )
    )
   )
   (struct.get $closure 0
    (local.get $f)
   )
  )
 )
)
