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

;; Check that we don't refine in ways that might require invalid exact casts
;; when custom descriptors is disabled.

;; RUN: wasm-opt %s -all                              --closed-world --preserve-type-order \
;; RUN:     --type-refining -S -o - | filecheck %s

;; RUN: wasm-opt %s -all --disable-custom-descriptors --closed-world --preserve-type-order \
;; RUN:     --type-refining -S -o - | filecheck %s --check-prefix=NO_CD

(module
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $foo (struct))
  ;; NO_CD:      (rec
  ;; NO_CD-NEXT:  (type $foo (struct))
  (type $foo (struct))
  ;; CHECK:       (type $bar (struct (field (mut (ref (exact $foo))))))
  ;; NO_CD:       (type $bar (struct (field (mut (ref $foo)))))
  (type $bar (struct (field (mut (ref null $foo)))))

  ;; CHECK:       (type $already-exact (struct (field (ref (exact $foo)))))
  ;; NO_CD:       (type $already-exact (struct (field (ref (exact $foo)))))
  (type $already-exact (struct (field (ref (exact $foo)))))

  ;; CHECK:      (tag $e (type $3))
  ;; NO_CD:      (tag $e (type $3))
  (tag $e)

  ;; CHECK:      (func $struct.new (type $4) (param $inexact (ref null $foo)) (param $exact (ref (exact $foo))) (result anyref)
  ;; CHECK-NEXT:  (struct.new $bar
  ;; CHECK-NEXT:   (ref.cast (ref (exact $foo))
  ;; CHECK-NEXT:    (try (result (ref null $foo))
  ;; CHECK-NEXT:     (do
  ;; CHECK-NEXT:      (struct.get $bar 0
  ;; CHECK-NEXT:       (struct.new $bar
  ;; CHECK-NEXT:        (local.get $exact)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (catch $e
  ;; CHECK-NEXT:      (local.get $inexact)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NO_CD:      (func $struct.new (type $4) (param $inexact (ref null $foo)) (param $exact (ref (exact $foo))) (result anyref)
  ;; NO_CD-NEXT:  (struct.new $bar
  ;; NO_CD-NEXT:   (ref.cast (ref $foo)
  ;; NO_CD-NEXT:    (try (result (ref null $foo))
  ;; NO_CD-NEXT:     (do
  ;; NO_CD-NEXT:      (struct.get $bar 0
  ;; NO_CD-NEXT:       (struct.new $bar
  ;; NO_CD-NEXT:        (local.get $exact)
  ;; NO_CD-NEXT:       )
  ;; NO_CD-NEXT:      )
  ;; NO_CD-NEXT:     )
  ;; NO_CD-NEXT:     (catch $e
  ;; NO_CD-NEXT:      (local.get $inexact)
  ;; NO_CD-NEXT:     )
  ;; NO_CD-NEXT:    )
  ;; NO_CD-NEXT:   )
  ;; NO_CD-NEXT:  )
  ;; NO_CD-NEXT: )
  (func $struct.new (param $inexact (ref null $foo)) (param $exact (ref (exact $foo))) (result anyref)
    (struct.new $bar
      (try (result (ref null $foo))
        (do
          (struct.get $bar 0
            (struct.new $bar
              (local.get $exact)
            )
          )
        )
        (catch $e
          (local.get $inexact)
        )
      )
    )
  )

  ;; CHECK:      (func $make-already-exact (type $5) (param $0 (ref (exact $foo))) (result (ref (exact $foo)))
  ;; CHECK-NEXT:  (struct.get $already-exact 0
  ;; CHECK-NEXT:   (struct.new $already-exact
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; NO_CD:      (func $make-already-exact (type $5) (param $0 (ref (exact $foo))) (result (ref (exact $foo)))
  ;; NO_CD-NEXT:  (struct.get $already-exact 0
  ;; NO_CD-NEXT:   (struct.new $already-exact
  ;; NO_CD-NEXT:    (local.get $0)
  ;; NO_CD-NEXT:   )
  ;; NO_CD-NEXT:  )
  ;; NO_CD-NEXT: )
  (func $make-already-exact (param (ref (exact $foo))) (result (ref (exact $foo)))
    ;; We should not accidentally remove exactness from a field that is already exact.
    (struct.get $already-exact 0
      (struct.new $already-exact
        (local.get 0)
      )
    )
  )
)
