;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.

;; RUN: foreach %s %t wasm-opt --directize -all -S -o - | filecheck %s

;; Call a subtype with the supertype. This call should succeed.
(module
 (rec
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $super (sub (func)))
  (type $super (sub (func)))
  ;; CHECK:       (type $sub (sub final $super (func)))
  (type $sub (sub final $super (func)))
 )

 ;; CHECK:      (table $table 93 funcref)
 (table $table 93 funcref)

 ;; CHECK:      (elem $elem (i32.const 0) $target)
 (elem $elem (i32.const 0) $target)

 ;; CHECK:      (export "caller" (func $caller))

 ;; CHECK:      (func $caller (type $0)
 ;; CHECK-NEXT:  (call $target)
 ;; CHECK-NEXT: )
 (func $caller (export "caller")
  ;; This turns into a direct call.
  (call_indirect (type $super)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $target (type $sub)
 ;; CHECK-NEXT: )
 (func $target (type $sub)
 )
)

;; Remove the subtyping. This call should error.
(module
 (rec
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $super (sub (func)))
  (type $super (sub (func)))
  ;; CHECK:       (type $other (sub (func)))
  (type $other (sub (func)))
 )

 ;; CHECK:      (table $table 93 funcref)
 (table $table 93 funcref)

 ;; CHECK:      (elem $elem (i32.const 0) $target)
 (elem $elem (i32.const 0) $target)

 ;; CHECK:      (export "caller" (func $caller))

 ;; CHECK:      (func $caller (type $0)
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $caller (export "caller")
  ;; This turns into an unreachable.
  (call_indirect (type $super)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $target (type $other)
 ;; CHECK-NEXT: )
 (func $target (type $other)
 )
)

;; Reverse the subtyping: Call a supertype with a subtype. This call should
;; fail.
(module
 (rec
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $super (sub (func)))
  (type $super (sub (func)))
  ;; CHECK:       (type $sub (sub final $super (func)))
  (type $sub (sub final $super (func)))
 )

 ;; CHECK:      (table $table 93 funcref)
 (table $table 93 funcref)

 ;; CHECK:      (elem $elem (i32.const 0) $target)
 (elem $elem (i32.const 0) $target)

 ;; CHECK:      (export "caller" (func $caller))

 ;; CHECK:      (func $caller (type $0)
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $caller (export "caller")
  ;; This turns into a direct call.
  (call_indirect (type $sub)
   (i32.const 0)
  )
 )

 ;; CHECK:      (func $target (type $super)
 ;; CHECK-NEXT: )
 (func $target (type $super)
 )
)

;; call_indirect using the supertype. The direct call has a more refined type,
;; which we must update the IR to.
(module
 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $super (sub (func (result (ref any)))))
  (type $super (sub (func (result (ref any)))))
  ;; CHECK:       (type $sub (sub $super (func (result (ref none)))))
  (type $sub (sub $super (func (result (ref none)))))
 )

 ;; CHECK:      (table $table 42 funcref)
 (table $table 42 funcref)
 ;; CHECK:      (elem $elem (i32.const 0) $sub)
 (elem $elem (i32.const 0) $sub)

 ;; CHECK:      (func $super (type $super) (result (ref any))
 ;; CHECK-NEXT:  (block $show-type (result (ref none))
 ;; CHECK-NEXT:   (call $sub)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $super (type $super) (result (ref any))
  (block $show-type (result (ref any))
   (call_indirect $table (type $super)
    (i32.const 0)
   )
  )
 )

 ;; CHECK:      (func $sub (type $sub) (result (ref none))
 ;; CHECK-NEXT:  (unreachable)
 ;; CHECK-NEXT: )
 (func $sub (type $sub) (result (ref none))
  (unreachable)
 )
)

