;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --closed-world --preserve-type-order \
;; RUN:     --unsubtyping --remove-unused-types -tnh -all -S -o - | filecheck %s

;; Because we assume traps never happen, we don't need to keep the descriptor to
;; preserve the trap in the global due to a null descriptor.
(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (sub (struct)))
    (type $A (sub (descriptor $A.desc) (struct)))
    ;; CHECK:       (type $A.desc (sub (struct)))
    (type $A.desc (sub (describes $A) (struct)))
  )

  ;; CHECK:      (global $A.desc (ref null (exact $A.desc)) (struct.new_default $A.desc))
  (global $A.desc (ref null (exact $A.desc)) (struct.new $A.desc))
  ;; CHECK:      (global $A (ref null $A) (struct.new_default $A))
  (global $A (ref null $A) (struct.new_desc $A (global.get $A.desc)))
)

;; Because we assume traps never happen, we do not need a ref.as_non_null to
;; preserve the trap when the descriptor is null.
(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (sub (struct)))
    (type $A (sub (descriptor $A.desc) (struct)))
    ;; CHECK:       (type $A.desc (sub (struct)))
    (type $A.desc (sub (describes $A) (struct)))
  )

  ;; CHECK:       (type $2 (func (param (ref null (exact $A.desc)))))

  ;; CHECK:      (func $nullable-descs (type $2) (param $A.desc (ref null (exact $A.desc)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result (ref (exact $A)))
  ;; CHECK-NEXT:    (struct.new_default $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nullable-descs (param $A.desc (ref null (exact $A.desc)))
    (drop
      (struct.new_desc $A
        (local.get $A.desc)
      )
    )
  )
)

;; Nested allocations do not need to be moved to new globals when traps never
;; happen.
(module
  (rec
    ;; CHECK:      (type $struct (sub (struct)))
    (type $struct (sub (descriptor $desc) (struct)))
    (type $desc (sub (describes $struct) (descriptor $meta) (struct)))
    (type $meta (sub (describes $desc) (struct)))
  )

  ;; CHECK:      (global $g (ref $struct) (struct.new_default $struct))
  (global $g (ref $struct) (struct.new_desc $struct (struct.new_desc $desc (ref.null none))))
)

;; Same, but now the nesting is under a non-descriptor field.
(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (sub (struct (field (ref $struct)))))
    (type $A (sub (struct (field (ref $struct)))))
    ;; CHECK:       (type $struct (sub (struct)))
    (type $struct (sub (descriptor $desc) (struct)))
    (type $desc (sub (describes $struct) (descriptor $meta) (struct)))
    (type $meta (sub (describes $desc) (struct)))
  )

  ;; CHECK:      (global $g (ref $A) (struct.new $A
  ;; CHECK-NEXT:  (struct.new_default $struct)
  ;; CHECK-NEXT: ))
  (global $g (ref $A) (struct.new $A (struct.new_desc $struct (struct.new_desc $desc (ref.null none)))))
)
