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

;; RUN: wasm-opt %s -all -o %t.text.wast -g -S
;; RUN: wasm-as %s -all -g -o %t.wasm
;; RUN: wasm-dis %t.wasm -all -o %t.bin.wast
;; RUN: wasm-as %s -all -o %t.nodebug.wasm
;; RUN: wasm-dis %t.nodebug.wasm -all -o %t.bin.nodebug.wast
;; RUN: cat %t.text.wast | filecheck %s --check-prefix=CHECK-TEXT
;; RUN: cat %t.bin.wast | filecheck %s --check-prefix=CHECK-BIN
;; RUN: cat %t.bin.nodebug.wast | filecheck %s --check-prefix=CHECK-BIN-NODEBUG

;; Test that we can roundtrip struct and array types
(module
  ;; Recursive structs
  ;; CHECK-TEXT:      (type $struct-rec-one (sub (struct (field (ref $struct-rec-one)))))
  ;; CHECK-BIN:      (type $struct-rec-one (sub (struct (field (ref $struct-rec-one)))))
  (type $struct-rec-one (sub (struct
    (field (ref $struct-rec-one))
  )))
  ;; CHECK-TEXT:      (type $struct-rec-two (sub $struct-rec-one (struct (field (ref $struct-rec-two)) (field (ref $struct-rec-two)))))
  ;; CHECK-BIN:      (type $struct-rec-two (sub $struct-rec-one (struct (field (ref $struct-rec-two)) (field (ref $struct-rec-two)))))
  (type $struct-rec-two (sub $struct-rec-one (struct
    (field (ref $struct-rec-two))
    (field (ref $struct-rec-two))
 )))

  ;; Non-recursive structs
  ;; CHECK-TEXT:      (type $struct-any (sub (struct (field (ref any)))))
  ;; CHECK-BIN:      (type $struct-any (sub (struct (field (ref any)))))
  (type $struct-any (sub (struct
    (field (ref any))
  )))
  ;; CHECK-TEXT:      (type $struct-i31 (sub $struct-any (struct (field (ref i31)))))
  ;; CHECK-BIN:      (type $struct-i31 (sub $struct-any (struct (field (ref i31)))))
  (type $struct-i31 (sub $struct-any (struct
    (field (ref i31))
 )))

  ;; Arrays
  ;; CHECK-TEXT:      (type $vector-any (sub (array (ref any))))
  ;; CHECK-BIN:      (type $vector-any (sub (array (ref any))))
  (type $vector-any (sub (array (ref any))))

  ;; CHECK-TEXT:      (type $vector-i32 (array i32))
  ;; CHECK-BIN:      (type $vector-i32 (array i32))
  (type $vector-i32 (array i32))

  ;; CHECK-TEXT:      (type $vector-i31 (sub $vector-any (array (ref i31))))
  ;; CHECK-BIN:      (type $vector-i31 (sub $vector-any (array (ref i31))))
  (type $vector-i31 (sub $vector-any (array (ref i31))))

  ;; CHECK-TEXT:      (type $struct-i31_any (sub $struct-i31 (struct (field (ref i31)) (field (ref any)))))
  ;; CHECK-BIN:      (type $struct-i31_any (sub $struct-i31 (struct (field (ref i31)) (field (ref any)))))
  (type $struct-i31_any (sub $struct-i31(struct
    (field (ref i31))
    (field (ref any))
 )))

  ;; CHECK-TEXT:      (type $8 (func (param (ref $vector-i32) (ref null $vector-i32))))

  ;; CHECK-TEXT:      (type $9 (func (param (ref $vector-i31) (ref $vector-any))))

  ;; CHECK-TEXT:      (type $10 (func (param (ref $struct-i31) (ref $struct-any))))

  ;; CHECK-TEXT:      (type $11 (func (param (ref $struct-i31) (ref $struct-i31_any))))

  ;; CHECK-TEXT:      (type $12 (func (param (ref $struct-rec-one) (ref $struct-rec-two))))

  ;; CHECK-TEXT:      (func $foo (type $8) (param $no-null (ref $vector-i32)) (param $yes-null (ref null $vector-i32))
  ;; CHECK-TEXT-NEXT:  (local.set $yes-null
  ;; CHECK-TEXT-NEXT:   (local.get $no-null)
  ;; CHECK-TEXT-NEXT:  )
  ;; CHECK-TEXT-NEXT: )
  ;; CHECK-BIN:      (type $8 (func (param (ref $vector-i32) (ref null $vector-i32))))

  ;; CHECK-BIN:      (type $9 (func (param (ref $vector-i31) (ref $vector-any))))

  ;; CHECK-BIN:      (type $10 (func (param (ref $struct-i31) (ref $struct-any))))

  ;; CHECK-BIN:      (type $11 (func (param (ref $struct-i31) (ref $struct-i31_any))))

  ;; CHECK-BIN:      (type $12 (func (param (ref $struct-rec-one) (ref $struct-rec-two))))

  ;; CHECK-BIN:      (func $foo (type $8) (param $no-null (ref $vector-i32)) (param $yes-null (ref null $vector-i32))
  ;; CHECK-BIN-NEXT:  (local.set $yes-null
  ;; CHECK-BIN-NEXT:   (local.get $no-null)
  ;; CHECK-BIN-NEXT:  )
  ;; CHECK-BIN-NEXT: )
  (func $foo (param $no-null (ref $vector-i32))
             (param $yes-null (ref null $vector-i32))
    ;; ok to set a non-nullable reference to a nullable target
    (local.set $yes-null (local.get $no-null))
  )

  ;; CHECK-TEXT:      (func $bar (type $9) (param $v-i31 (ref $vector-i31)) (param $v-any (ref $vector-any))
  ;; CHECK-TEXT-NEXT:  (local.set $v-any
  ;; CHECK-TEXT-NEXT:   (local.get $v-i31)
  ;; CHECK-TEXT-NEXT:  )
  ;; CHECK-TEXT-NEXT: )
  ;; CHECK-BIN:      (func $bar (type $9) (param $v-i31 (ref $vector-i31)) (param $v-any (ref $vector-any))
  ;; CHECK-BIN-NEXT:  (local.set $v-any
  ;; CHECK-BIN-NEXT:   (local.get $v-i31)
  ;; CHECK-BIN-NEXT:  )
  ;; CHECK-BIN-NEXT: )
  (func $bar (param $v-i31 (ref $vector-i31))
             (param $v-any (ref $vector-any))
    ;; ok to set a vector of (immutable) i31s to a vector of anyies
    (local.set $v-any (local.get $v-i31))
  )

  ;; CHECK-TEXT:      (func $baz (type $10) (param $s-i31 (ref $struct-i31)) (param $s-any (ref $struct-any))
  ;; CHECK-TEXT-NEXT:  (local.set $s-any
  ;; CHECK-TEXT-NEXT:   (local.get $s-i31)
  ;; CHECK-TEXT-NEXT:  )
  ;; CHECK-TEXT-NEXT: )
  ;; CHECK-BIN:      (func $baz (type $10) (param $s-i31 (ref $struct-i31)) (param $s-any (ref $struct-any))
  ;; CHECK-BIN-NEXT:  (local.set $s-any
  ;; CHECK-BIN-NEXT:   (local.get $s-i31)
  ;; CHECK-BIN-NEXT:  )
  ;; CHECK-BIN-NEXT: )
  (func $baz (param $s-i31 (ref $struct-i31))
             (param $s-any (ref $struct-any))
    ;; ok to set a struct of an (immutable) i31 to a one of an any
    (local.set $s-any (local.get $s-i31))
  )

  ;; CHECK-TEXT:      (func $boo (type $11) (param $s-i31 (ref $struct-i31)) (param $s-i31_any (ref $struct-i31_any))
  ;; CHECK-TEXT-NEXT:  (local.set $s-i31
  ;; CHECK-TEXT-NEXT:   (local.get $s-i31_any)
  ;; CHECK-TEXT-NEXT:  )
  ;; CHECK-TEXT-NEXT: )
  ;; CHECK-BIN:      (func $boo (type $11) (param $s-i31 (ref $struct-i31)) (param $s-i31_any (ref $struct-i31_any))
  ;; CHECK-BIN-NEXT:  (local.set $s-i31
  ;; CHECK-BIN-NEXT:   (local.get $s-i31_any)
  ;; CHECK-BIN-NEXT:  )
  ;; CHECK-BIN-NEXT: )
  (func $boo (param $s-i31 (ref $struct-i31))
             (param $s-i31_any (ref $struct-i31_any))
    ;; also ok to have extra fields
    (local.set $s-i31 (local.get $s-i31_any))
  )

  ;; CHECK-TEXT:      (func $coinductive (type $12) (param $rec-one (ref $struct-rec-one)) (param $rec-two (ref $struct-rec-two))
  ;; CHECK-TEXT-NEXT:  (local.set $rec-one
  ;; CHECK-TEXT-NEXT:   (local.get $rec-two)
  ;; CHECK-TEXT-NEXT:  )
  ;; CHECK-TEXT-NEXT: )
  ;; CHECK-BIN:      (func $coinductive (type $12) (param $rec-one (ref $struct-rec-one)) (param $rec-two (ref $struct-rec-two))
  ;; CHECK-BIN-NEXT:  (local.set $rec-one
  ;; CHECK-BIN-NEXT:   (local.get $rec-two)
  ;; CHECK-BIN-NEXT:  )
  ;; CHECK-BIN-NEXT: )
  (func $coinductive (param $rec-one (ref $struct-rec-one))
                     (param $rec-two (ref $struct-rec-two))
    ;; Do not infinitely recurse when determining this subtype relation!
    (local.set $rec-one (local.get $rec-two))
  )
)
;; CHECK-BIN-NODEBUG:      (type $0 (sub (struct (field (ref $0)))))

;; CHECK-BIN-NODEBUG:      (type $1 (sub $0 (struct (field (ref $1)) (field (ref $1)))))

;; CHECK-BIN-NODEBUG:      (type $2 (sub (struct (field (ref any)))))

;; CHECK-BIN-NODEBUG:      (type $3 (sub $2 (struct (field (ref i31)))))

;; CHECK-BIN-NODEBUG:      (type $4 (sub (array (ref any))))

;; CHECK-BIN-NODEBUG:      (type $5 (array i32))

;; CHECK-BIN-NODEBUG:      (type $6 (sub $4 (array (ref i31))))

;; CHECK-BIN-NODEBUG:      (type $7 (sub $3 (struct (field (ref i31)) (field (ref any)))))

;; CHECK-BIN-NODEBUG:      (type $8 (func (param (ref $5) (ref null $5))))

;; CHECK-BIN-NODEBUG:      (type $9 (func (param (ref $6) (ref $4))))

;; CHECK-BIN-NODEBUG:      (type $10 (func (param (ref $3) (ref $2))))

;; CHECK-BIN-NODEBUG:      (type $11 (func (param (ref $3) (ref $7))))

;; CHECK-BIN-NODEBUG:      (type $12 (func (param (ref $0) (ref $1))))

;; CHECK-BIN-NODEBUG:      (func $0 (type $8) (param $0 (ref $5)) (param $1 (ref null $5))
;; CHECK-BIN-NODEBUG-NEXT:  (local.set $1
;; CHECK-BIN-NODEBUG-NEXT:   (local.get $0)
;; CHECK-BIN-NODEBUG-NEXT:  )
;; CHECK-BIN-NODEBUG-NEXT: )

;; CHECK-BIN-NODEBUG:      (func $1 (type $9) (param $0 (ref $6)) (param $1 (ref $4))
;; CHECK-BIN-NODEBUG-NEXT:  (local.set $1
;; CHECK-BIN-NODEBUG-NEXT:   (local.get $0)
;; CHECK-BIN-NODEBUG-NEXT:  )
;; CHECK-BIN-NODEBUG-NEXT: )

;; CHECK-BIN-NODEBUG:      (func $2 (type $10) (param $0 (ref $3)) (param $1 (ref $2))
;; CHECK-BIN-NODEBUG-NEXT:  (local.set $1
;; CHECK-BIN-NODEBUG-NEXT:   (local.get $0)
;; CHECK-BIN-NODEBUG-NEXT:  )
;; CHECK-BIN-NODEBUG-NEXT: )

;; CHECK-BIN-NODEBUG:      (func $3 (type $11) (param $0 (ref $3)) (param $1 (ref $7))
;; CHECK-BIN-NODEBUG-NEXT:  (local.set $0
;; CHECK-BIN-NODEBUG-NEXT:   (local.get $1)
;; CHECK-BIN-NODEBUG-NEXT:  )
;; CHECK-BIN-NODEBUG-NEXT: )

;; CHECK-BIN-NODEBUG:      (func $4 (type $12) (param $0 (ref $0)) (param $1 (ref $1))
;; CHECK-BIN-NODEBUG-NEXT:  (local.set $0
;; CHECK-BIN-NODEBUG-NEXT:   (local.get $1)
;; CHECK-BIN-NODEBUG-NEXT:  )
;; CHECK-BIN-NODEBUG-NEXT: )
