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

(module
  ;; CHECK:      (type $externs (array (mut externref)))
  (type $externs (array (mut externref)))
  ;; CHECK:      (type $funcs (array (mut funcref)))
  (type $funcs (array (mut funcref)))
  ;; CHECK:      (type $bytes (array (mut i8)))
  (type $bytes (array (mut i8)))

  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $super (sub (func (param i32 i64))))

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

  ;; CHECK:       (type $not-configured (sub $super (func (param i32 i64))))

  ;; CHECK:       (type $configured (sub $super (func (param i32 i64))))

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

  ;; CHECK:      (type $configureAll (func (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
  (type $configureAll (func (param (ref null $externs)
                                   (ref null $funcs)
                                   (ref null $bytes)
                                   externref)))

  (rec
    (type $super (sub (func (param i32 i64))))
    (type $configured (sub $super (func (param i32 i64))))
    (type $not-configured (sub $super (func (param i32 i64))))
  )

  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $9 (func (param i32)))

  ;; CHECK:       (type $10 (struct))

  ;; CHECK:      (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $externs) (ref null $funcs) (ref null $bytes) externref)))
  (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll)))

  ;; CHECK:      (data $bytes "12345678")
  (data $bytes "12345678")

  ;; CHECK:      (elem $externs externref (item (ref.null noextern)))
  (elem $externs externref
    (ref.null noextern)
  )

  ;; CHECK:      (elem $funcs func $configured)
  (elem $funcs funcref
    (ref.func $configured)
  )

  ;; CHECK:      (elem declare func $referenced-not-configured)

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

  ;; CHECK:      (func $start (type $4)
  ;; CHECK-NEXT:  (call $configureAll
  ;; CHECK-NEXT:   (array.new_elem $externs $externs
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (array.new_elem $funcs $funcs
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (array.new_data $bytes $bytes
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (i32.const 8)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (ref.null noextern)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $start
    (call $configureAll
      (array.new_elem $externs $externs
        (i32.const 0)
        (i32.const 1)
      )
      (array.new_elem $funcs $funcs
        (i32.const 0)
        (i32.const 1)
      )
      (array.new_data $bytes $bytes
        (i32.const 0)
        (i32.const 8)
      )
      (ref.null noextern)
    )
  )

  ;; CHECK:      (func $configured (type $configured) (param $0 i32) (param $1 i64)
  ;; CHECK-NEXT: )
  (func $configured (type $configured) (param i32 i64)
    ;; Even though we do not use the parameters, they must be kept so the
    ;; function can be called as expected outside the module.
  )

  ;; CHECK:      (func $referenced-not-configured (type $not-configured) (param $0 i32) (param $1 i64)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.func $referenced-not-configured)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $referenced-not-configured (type $not-configured) (param i32 i64)
    ;; This referenced function has a type in the same tree, so it also cannot
    ;; be optimized.
    (drop
      (ref.func $referenced-not-configured)
    )
  )

  ;; CHECK:      (func $unreferenced (type $4)
  ;; CHECK-NEXT:  (local $0 i64)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT: )
  (func $unreferenced (type $configured) (param i32 i64)
    ;; This unreferenced function can be optimized even though it has the same
    ;; type as a configured function.
  )

  ;; CHECK:      (func $call-configured (type $9) (param $0 i32)
  ;; CHECK-NEXT:  (call $configured
  ;; CHECK-NEXT:   (local.get $0)
  ;; CHECK-NEXT:   (i64.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $call-configured (param i32)
    ;; The parameter must be kept because it is used when calling the configured
    ;; function, which keeps its parameter.
    (call $configured
      (local.get 0)
      (i64.const 1)
    )
  )
)
