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

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

(module
  ;; CHECK:      (type $A (struct))
  (type $A (struct))
  ;; CHECK:      (type $B (struct (field i32)))
  (type $B (struct (field i32)))
  ;; CHECK:      (type $2 (func (param externref)))

  ;; CHECK:      (type $3 (func (result externref)))

  ;; CHECK:      (type $4 (func (param anyref) (result anyref)))

  ;; CHECK:      (type $5 (func (param externref) (result externref)))

  ;; CHECK:      (type $C (struct (field i32) (field f64)))
  (type $C (struct (field i32 f64)))

  ;; CHECK:      (type $7 (func (param i32) (result f64)))

  ;; CHECK:      (type $8 (func (param anyref)))

  ;; CHECK:      (type $9 (func (result anyref)))

  ;; CHECK:      (type $10 (func (param (ref $A) (ref null $B)) (result (ref $C))))

  ;; CHECK:      (type $11 (func (param i32 (ref $A) funcref)))

  ;; CHECK:      (type $12 (func (param externref externref) (result externref)))

  ;; CHECK:      (type $13 (func (param i32 externref funcref)))

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

  ;; CHECK:      (export "externref-param" (func $externref-param))

  ;; CHECK:      (export "externref-result" (func $externref-result))

  ;; CHECK:      (export "anyref-param" (func $stub$anyref-param))

  ;; CHECK:      (export "anyref-result" (func $stub$anyref-result))

  ;; CHECK:      (export "anyref-both" (func $stub$anyref-both))

  ;; CHECK:      (export "anyref-both-dupe" (func $stub$anyref-both-dupe))

  ;; CHECK:      (export "many" (func $stub$many))

  ;; CHECK:      (export "mixed" (func $stub$mixed))

  ;; CHECK:      (func $normal (type $7) (param $x i32) (result f64)
  ;; CHECK-NEXT:  (f64.const 3.14159)
  ;; CHECK-NEXT: )
  (func $normal (export "normal") (param $x i32) (result f64)
    ;; A normal function which we do not need to do anything with.
    (f64.const 3.14159)
  )

  ;; CHECK:      (func $externref-param (type $2) (param $x externref)
  ;; CHECK-NEXT: )
  (func $externref-param (export "externref-param") (param $x externref)
    ;; An externref param is fine, we don't need to do anything.
  )

  ;; CHECK:      (func $externref-result (type $3) (result externref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $externref-result (export "externref-result") (result externref)
    ;; An externref result is also fine.
    (unreachable)
  )

  ;; CHECK:      (func $anyref-param (type $8) (param $x anyref)
  ;; CHECK-NEXT: )
  (func $anyref-param (export "anyref-param") (param $x anyref)
    ;; An anyref requires a fixup. We will call this from a stub that has an
    ;; externref param, which calls this.
  )

  ;; CHECK:      (func $anyref-result (type $9) (result anyref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $anyref-result (export "anyref-result") (result anyref)
    ;; An anyref result also requires a fixup.
    (unreachable)
  )

  ;; CHECK:      (func $anyref-both (type $4) (param $x anyref) (result anyref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $anyref-both (export "anyref-both") (param $x anyref) (result anyref)
    ;; Here we must fix up both the param and the result.
    (unreachable)
  )

  ;; CHECK:      (func $anyref-both-dupe (type $4) (param $x anyref) (result anyref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $anyref-both-dupe (export "anyref-both-dupe") (param $x anyref) (result anyref)
    ;; Identical to the above function, and should be fixed up in the same
    ;; manner. In theory we could use the same stub for both, but we leave that
    ;; for the optimizer.
    (unreachable)
  )

  ;; CHECK:      (func $many (type $10) (param $a (ref $A)) (param $b (ref null $B)) (result (ref $C))
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $many (export "many") (param $a (ref $A)) (param $b (ref null $B)) (result (ref $C))
    ;; Various declared types are used, and must be fixed up.
    (unreachable)
  )

  ;; CHECK:      (func $mixed (type $11) (param $a i32) (param $b (ref $A)) (param $c funcref)
  ;; CHECK-NEXT: )
  (func $mixed (export "mixed") (param $a i32) (param $b (ref $A)) (param $c funcref)
    ;; One param needs to be fixed, two others do not: we can ignore i32 and
    ;; funcref.
  )
)

;; CHECK:      (func $stub$anyref-param (type $2) (param $0 externref)
;; CHECK-NEXT:  (call $anyref-param
;; CHECK-NEXT:   (ref.cast anyref
;; CHECK-NEXT:    (any.convert_extern
;; CHECK-NEXT:     (local.get $0)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$anyref-result (type $3) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $anyref-result)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$anyref-both (type $5) (param $0 externref) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $anyref-both
;; CHECK-NEXT:    (ref.cast anyref
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$anyref-both-dupe (type $5) (param $0 externref) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $anyref-both-dupe
;; CHECK-NEXT:    (ref.cast anyref
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$many (type $12) (param $0 externref) (param $1 externref) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $many
;; CHECK-NEXT:    (ref.cast (ref $A)
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:    (ref.cast (ref null $B)
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $1)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$mixed (type $13) (param $0 i32) (param $1 externref) (param $2 funcref)
;; CHECK-NEXT:  (call $mixed
;; CHECK-NEXT:   (local.get $0)
;; CHECK-NEXT:   (ref.cast (ref $A)
;; CHECK-NEXT:    (any.convert_extern
;; CHECK-NEXT:     (local.get $1)
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:   (local.get $2)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
  ;; Two exports of a single function that needs fixups. We could reuse a
  ;; single stub, but we leave that for the optimizer.

  (export "a" (func $anyref-both))

  (export "b" (func $anyref-both))

  ;; CHECK:      (type $0 (func (param externref) (result externref)))

  ;; CHECK:      (type $1 (func (param anyref) (result anyref)))

  ;; CHECK:      (export "a" (func $stub$anyref-both))

  ;; CHECK:      (export "b" (func $stub$anyref-both_2))

  ;; CHECK:      (func $anyref-both (type $1) (param $x anyref) (result anyref)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $anyref-both (param $x anyref) (result anyref)
    (unreachable)
  )
)
;; CHECK:      (func $stub$anyref-both (type $0) (param $0 externref) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $anyref-both
;; CHECK-NEXT:    (ref.cast anyref
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $stub$anyref-both_2 (type $0) (param $0 externref) (result externref)
;; CHECK-NEXT:  (extern.convert_any
;; CHECK-NEXT:   (call $anyref-both
;; CHECK-NEXT:    (ref.cast anyref
;; CHECK-NEXT:     (any.convert_extern
;; CHECK-NEXT:      (local.get $0)
;; CHECK-NEXT:     )
;; CHECK-NEXT:    )
;; CHECK-NEXT:   )
;; CHECK-NEXT:  )
;; CHECK-NEXT: )