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

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

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (type $1 (func (result funcref)))

  ;; CHECK:      (elem declare func $foo)

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

  ;; $foo should not be removed after being inlined, because there is 'ref.func'
  ;; instruction that refers to it
  ;; CHECK:      (func $foo (type $0)
  ;; CHECK-NEXT: )
  (func $foo)

  ;; CHECK:      (func $ref_func_test (type $1) (result funcref)
  ;; CHECK-NEXT:  (block $__inlined_func$foo
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (ref.func $foo)
  ;; CHECK-NEXT: )
  (func $ref_func_test (result funcref)
    (call $foo)
    (ref.func $foo)
  )
)

(module
 ;; a function reference in a global's init should be noticed, and prevent us
 ;; from removing an inlined function

 ;; CHECK:      (type $0 (func (result i32)))

 ;; CHECK:      (global $global$0 (mut funcref) (ref.func $0))
 (global $global$0 (mut funcref) (ref.func $0))

 ;; CHECK:      (func $0 (type $0) (result i32)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: )
 (func $0 (result i32)
  (i32.const 1337)
 )

 ;; CHECK:      (func $1 (type $0) (result i32)
 ;; CHECK-NEXT:  (block $__inlined_func$0 (result i32)
 ;; CHECK-NEXT:   (i32.const 1337)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $1 (result i32)
  (call $0)
 )
)

(module
 ;; a function reference in the start should be noticed, and prevent us
 ;; from removing an inlined function

 ;; CHECK:      (type $0 (func))

 ;; CHECK:      (start $0)
 (start $0)

 ;; CHECK:      (func $0 (type $0)
 ;; CHECK-NEXT:  (nop)
 ;; CHECK-NEXT: )
 (func $0
  (nop)
 )

 ;; CHECK:      (func $1 (type $0)
 ;; CHECK-NEXT:  (block $__inlined_func$0
 ;; CHECK-NEXT:   (nop)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $1
  (call $0)
 )
)

;; inline a return_call_ref
(module
 ;; CHECK:      (type $none_=>_none (func))
 (type $none_=>_none (func))

 ;; CHECK:      (export "func_36_invoker" (func $1))
 (export "func_36_invoker" (func $1))

 (func $0
  (return_call_ref $none_=>_none
   (ref.null $none_=>_none)
  )
 )
 ;; CHECK:      (func $1 (type $none_=>_none)
 ;; CHECK-NEXT:  (block $__inlined_func$0
 ;; CHECK-NEXT:   (block ;; (replaces unreachable CallRef we can't emit)
 ;; CHECK-NEXT:    (drop
 ;; CHECK-NEXT:     (ref.null nofunc)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:    (unreachable)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $1
  (call $0)
 )
)

;; handle non-nullable parameter types (which turn into local types after
;; inlining)
(module
 (func $0 (param $non-null (ref func)) (result (ref func))
  (local.get $non-null)
 )

 ;; CHECK:      (type $0 (func (result (ref func))))

 ;; CHECK:      (elem declare func $1)

 ;; CHECK:      (func $1 (type $0) (result (ref func))
 ;; CHECK-NEXT:  (local $0 (ref func))
 ;; CHECK-NEXT:  (block $__inlined_func$0 (result (ref func))
 ;; CHECK-NEXT:   (local.set $0
 ;; CHECK-NEXT:    (ref.func $1)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (local.get $0)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $1 (result (ref func))
  (call $0
   (ref.func $1)
  )
 )
)

;; Test handling of nested inlined calls.
(module
 (func $callee-a (param i32))

 (func $callee-b (param $x i32) (result i32)
  (local.get $x)
 )

 ;; CHECK:      (type $0 (func))

 ;; CHECK:      (func $caller-with-pop-twice (type $0)
 ;; CHECK-NEXT:  (local $0 i32)
 ;; CHECK-NEXT:  (local $1 i32)
 ;; CHECK-NEXT:  (block $__inlined_func$callee-a$1
 ;; CHECK-NEXT:   (local.set $1
 ;; CHECK-NEXT:    (block $__inlined_func$callee-b (result i32)
 ;; CHECK-NEXT:     (local.set $0
 ;; CHECK-NEXT:      (i32.const 42)
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:     (local.get $0)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (block
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $caller-with-pop-twice
  ;; Both these calls should be inlined.
  (call $callee-a
   (call $callee-b
    (i32.const 42)
   )
  )
 )
)