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

;; RUN: foreach %s %t wasm-opt --experimental-type-generalizing -all -S -o - | filecheck %s

;; Test that visitStructSet correctly handles structs with non-ref fields
;; without corrupting the backward analysis stack.
(module
  ;; CHECK:      (type $s (struct (field $x (mut i32)) (field $r (mut anyref))))
  (type $s (struct (field $x (mut i32)) (field $r (mut anyref))))

  ;; CHECK:      (type $1 (func (param (ref null $s) anyref)))

  ;; CHECK:      (func $struct-set-nonref-field (type $1) (param $obj (ref null $s)) (param $r anyref)
  ;; CHECK-NEXT:  (struct.set $s $x
  ;; CHECK-NEXT:   (local.get $obj)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $s $r
  ;; CHECK-NEXT:   (local.get $obj)
  ;; CHECK-NEXT:   (local.get $r)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $struct-set-nonref-field (param $obj (ref null $s)) (param $r anyref)
    ;; Setting a non-ref field (i32) should not push i32 onto the type
    ;; requirement stack, which would corrupt subsequent ref type tracking.
    (struct.set $s $x
      (local.get $obj)
      (i32.const 10)
    )
    (struct.set $s $r
      (local.get $obj)
      (local.get $r)
    )
  )
)

;; Test that visitRefAs handles the case where the stack is empty (no
;; downstream type requirement) without crashing.
(module
  ;; CHECK:      (type $0 (func (param anyref)))

  ;; CHECK:      (func $ref-as-non-null-dropped (type $0) (param $x anyref)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-as-non-null-dropped (param $x anyref)
    ;; The result of ref.as_non_null is dropped, so no downstream type
    ;; requirement exists. This should not crash.
    (drop
      (ref.as_non_null
        (local.get $x)
      )
    )
  )
)

;; Test extern.convert_any with dropped result.
(module
  ;; CHECK:      (type $0 (func (param anyref)))

  ;; CHECK:      (func $any-convert-extern-dropped (type $0) (param $x anyref)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (any.convert_extern
  ;; CHECK-NEXT:    (extern.convert_any
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $any-convert-extern-dropped (param $x anyref)
    ;; Dropped extern.convert_any / any.convert_extern chain should not crash.
    (drop
      (any.convert_extern
        (extern.convert_any
          (local.get $x)
        )
      )
    )
  )
)
