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

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

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new_default $A)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Copy the default value from $A to $B. Note that we do not detect that $B
    ;; is never allocated in this pass.
    (local $A (ref $A))
    (local.set $A
      (struct.new_default $A)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Same, but copy a non-default value.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (block (result (ref $B))
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (ref.as_non_null
  ;; CHECK-NEXT:       (local.get $A)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 10)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Now the copy has to look through fallthroughs on both the source and
    ;; destination.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    (struct.set $B 0
      (block (result (ref null $B))
        (local.get $B)
      )
      (block (result i32)
        (struct.get $A 0
          (local.get $A)
        )
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $B
  ;; CHECK-NEXT:   (struct.new $B
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Now copy from $A to $B, but also allocate a $B with a matching value. We
    ;; should still optimize.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    ;; This is new.
    (local.set $B
      (struct.new $B
        (i32.const 10)
      )
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Now instead of allocating $B with the same value, we set $B with the same
    ;; value. We can still optimize.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    ;; This is a set now.
    (struct.set $B 0
      (local.get $B)
      (i32.const 10)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $B
  ;; CHECK-NEXT:   (struct.new $B
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Same, but now allocate $B with a conflicting value. We cannot optimize.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    (local.set $B
      (struct.new $B
        ;; Does not match.
        (i32.const 20)
      )
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This cannot be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local $A (ref $A))
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $B (ref $B)) (result i32)
    ;; Same, but now the conflicting value comes from a set rather than an
    ;; allocation.
    (local $A (ref $A))
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    ;; This is a set now.
    (struct.set $B 0
      (local.get $B)
      (i32.const 20)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This cannot be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; Now the copied value comes from a set.
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; The copied value comes from both a set and an allocation, but they match.
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (local.set $A
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (struct.get $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; Now the source values don't match, so we cannot optimize.
    (local.set $A
      (struct.new $A
        (i32.const 10)
      )
    )
    (struct.set $A 0
      (local.get $A)
      (i32.const 20)
    )
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; This should be optimized.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $other) (ref $struct))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $other (ref $other)) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $struct (ref $struct))
    ;; Copy from $other to $struct.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    ;; We never wrote to $super, so the only value we can read from it is what
    ;; was written to $struct (which also may have been a $sub at runtime).
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $other) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
    ;; Same as above, but now we copy to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))

    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $5 (func))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref $struct))))

  ;; CHECK:      (func $init (type $5)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above, but now with a different value in the subtype $sub1. We
    ;; also add an additional subtype, $sub2, which can still be optimized.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (drop
      (struct.new $sub1
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $struct (ref $struct))
    ;; Copy from $other to $struct.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 0
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    ;; The copy might have written to $sub1 or $sub2, but only $sub2 does not
    ;; already have another conflicting value. We can optimize $sub2 but not
    ;; $sub1.
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 0
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))

    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $5 (func))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $5)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (drop
      (struct.new $sub1
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
    ;; Now the copy is to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))

    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $5 (func))

  ;; CHECK:      (type $6 (func (param (ref $sub1))))

  ;; CHECK:      (type $7 (func (param (ref $other) (ref $struct))))

  ;; CHECK:      (func $init (type $6) (param $sub1 (ref $sub1))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $sub1 0
  ;; CHECK-NEXT:   (local.get $sub1)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $sub1 (ref $sub1))
    ;; Now the value is set to an inexact reference to $sub1. This won't make a
    ;; difference.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (struct.set $sub1 0
      (local.get $sub1)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $copy (type $7) (param $other (ref $other)) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $struct (ref $struct))
    ;; Copy from $other to $struct.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 0
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 0
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))

    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $5 (func))

  ;; CHECK:      (type $6 (func (param (ref $sub1))))

  ;; CHECK:      (type $7 (func (param (ref $other) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $6) (param $sub1 (ref $sub1))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $sub1 0
  ;; CHECK-NEXT:   (local.get $sub1)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $sub1 (ref $sub1))
    ;; Same as above.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (struct.set $sub1 0
      (local.get $sub1)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $copy (type $7) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
    ;; Now the copy is to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $5)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $other) (ref $struct))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $super
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Now the different value is in $super. Since it's set in an exact $super,
    ;; it won't interfere with the copy.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (drop
      (struct.new $super
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $other (ref $other)) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $struct (ref $struct))
    ;; Copy from $other to $struct.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $other) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $super
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (drop
      (struct.new $super
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
    ;; Copy from $other to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $super))))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref $struct))))

  ;; CHECK:      (func $init (type $5) (param $super (ref $super))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $super (ref $super))
    ;; Now the different value is in an inexact $super.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (struct.set $super 0
      (local.get $super)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $struct (ref $struct))
    ;; Copy from $other to $struct.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub 0
  ;; CHECK-NEXT:    (local.get $sub)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub 0
  ;; CHECK-NEXT:    (local.get $sub)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $super))))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $5) (param $super (ref $super))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $super (ref $super))
    ;; Same as above.
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
    (struct.set $super 0
      (local.get $super)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-struct (ref (exact $struct)))
    ;; Copy from $other to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 0
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 0
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct)))
    (type $super (sub (struct)))
    ;; CHECK:       (type $A (sub $super (struct (field (mut i32)))))
    (type $A (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $B (sub $super (struct (field (mut i32)))))
    (type $B (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $super))))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref $A))))

  ;; CHECK:      (func $init (type $5) (param $super (ref $super))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $super (ref $super))
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $A (ref $A))
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $A (ref $A))
    ;; Copy from $other to $A. The fact that the field is missing in $super
    ;; should not cause problems.
    (struct.set $A 0
      (local.get $A)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $B (ref null $B))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $A (ref null $A))
    (local $B (ref null $B))
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $A (ref null (exact $A)))
  ;; CHECK-NEXT:  (local $B (ref null (exact $B)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $A (ref null (exact $A)))
    (local $B (ref null (exact $B)))
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct)))
    (type $super (sub (struct)))
    ;; CHECK:       (type $A (sub $super (struct (field (mut i32)))))
    (type $A (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $B (sub $super (struct (field (mut i32)))))
    (type $B (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $other (struct (field (mut i32))))
    (type $other (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $super))))

  ;; CHECK:      (type $6 (func (param (ref $other) (ref (exact $A)))))

  ;; CHECK:      (func $init (type $5) (param $super (ref $super))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $other
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $super (ref $super))
    (drop
      (struct.new $other
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $6) (param $other (ref $other)) (param $exact-A (ref (exact $A)))
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $exact-A)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $other (ref $other)) (param $exact-A (ref (exact $A)))
    ;; Same as above, but now the copy is to exact $A.
    (struct.set $A 0
      (local.get $exact-A)
      (struct.get $other 0
        (local.get $other)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $B (ref null $B))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $A (ref null $A))
    (local $B (ref null $B))
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $A (ref null (exact $A)))
  ;; CHECK-NEXT:  (local $B (ref null (exact $B)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $A (ref null (exact $A)))
    (local $B (ref null (exact $B)))
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $sub1
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $struct (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct))
    ;; Copy from $struct to itself. This propagates the write from $sub1 to
    ;; $sub2.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $sub1
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
    ;; Now copy from $struct to exact $struct. This does not propagate to $sub2.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $sub1
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $struct)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $exact-struct (ref (exact $struct)))
    ;; Now copy from exact $struct to $struct. This does nothing, since exact
    ;; $struct is not written to originally.
    (struct.set $struct 0
      (local.get $struct)
      (struct.get $struct 0
        (local.get $exact-struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref (exact $struct)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above.
    (drop
      (struct.new $sub1
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $exact-struct (ref (exact $struct)))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $exact-struct)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $exact-struct (ref (exact $struct)))
    ;; Now copy from exact $struct to exact $struct.
    (struct.set $struct 0
      (local.get $exact-struct)
      (struct.get $struct 0
        (local.get $exact-struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $struct2 (sub $super (struct (field (mut i32)))))
    (type $struct2 (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref $super))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $sub
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $struct (ref $struct)) (param $super (ref $super))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $super (ref $super))
    ;; Copy from $struct to $super.
    (struct.set $super 0
      (local.get $super)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $struct2 (ref null $struct2))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $struct2 (ref null $struct2))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $struct2 (ref null (exact $struct2)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $struct2 (ref null (exact $struct2)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $struct2 (sub $super (struct (field (mut i32)))))
    (type $struct2 (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref (exact $super)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $sub
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $struct (ref $struct)) (param $exact-super (ref (exact $super)))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $exact-super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $exact-super (ref (exact $super)))
    ;; Copy from $struct to exact $super.
    (struct.set $super 0
      (local.get $exact-super)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $struct2 (ref null $struct2))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $struct2 (ref null $struct2))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $struct2 (ref null (exact $struct2)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $struct2 (ref null (exact $struct2)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $struct2 (sub $super (struct (field (mut i32)))))
    (type $struct2 (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref (exact $struct)) (ref $super))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $sub
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $exact-struct (ref (exact $struct))) (param $super (ref $super))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $exact-struct (ref (exact $struct))) (param $super (ref $super))
    ;; Copy from exact $struct to $super.
    (struct.set $super 0
      (local.get $super)
      (struct.get $struct 0
        (local.get $exact-struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $struct2 (ref null $struct2))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $struct2 (ref null $struct2))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $struct2 (ref null (exact $struct2)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $struct2 (ref null (exact $struct2)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $struct2 (sub $super (struct (field (mut i32)))))
    (type $struct2 (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $struct (struct (field (mut i32)))))
    (type $sub (sub $struct (struct (field (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref (exact $struct)) (ref (exact $super)))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $sub
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $exact-struct (ref (exact $struct))) (param $exact-super (ref (exact $super)))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $exact-super)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $exact-struct (ref (exact $struct))) (param $exact-super (ref (exact $super)))
    ;; Copy from exact $struct to exact $super.
    (struct.set $super 0
      (local.get $exact-super)
      (struct.get $struct 0
        (local.get $exact-struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $struct2 (ref null $struct2))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $struct2 (ref null $struct2))
    (local $sub (ref null $sub))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $4)
  ;; CHECK-NEXT:  (local $super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $struct (ref null (exact $struct)))
  ;; CHECK-NEXT:  (local $struct2 (ref null (exact $struct2)))
  ;; CHECK-NEXT:  (local $sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $struct2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $super (ref null (exact $super)))
    (local $struct (ref null (exact $struct)))
    (local $struct2 (ref null (exact $struct2)))
    (local $sub (ref null (exact $sub)))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $struct2 0
        (local.get $struct2)
      )
    )
    (drop
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $struct (sub (struct (field (mut i32)))))
    (type $struct (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $struct) (ref $sub1))))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $struct
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4) (param $struct (ref $struct)) (param $sub1 (ref $sub1))
  ;; CHECK-NEXT:  (struct.set $sub1 0
  ;; CHECK-NEXT:   (local.get $sub1)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $sub1 (ref $sub1))
    ;; Copy from $struct to $sub1.
    (struct.set $sub1 0
      (local.get $sub1)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $3)
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $3)
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $struct (ref null $struct))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $struct (sub (struct (field (mut i32)))))
    (type $struct (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32)))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $struct) (ref (exact $sub1)))))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $struct
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4) (param $struct (ref $struct)) (param $exact-sub1 (ref (exact $sub1)))
  ;; CHECK-NEXT:  (struct.set $sub1 0
  ;; CHECK-NEXT:   (local.get $exact-sub1)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $struct (ref $struct)) (param $exact-sub1 (ref (exact $sub1)))
    ;; Copy from $struct to exact $sub1.
    (struct.set $sub1 0
      (local.get $exact-sub1)
      (struct.get $struct 0
        (local.get $struct)
      )
    )
  )

  ;; CHECK:      (func $gets (type $3)
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $gets
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $exact-gets (type $3)
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null (exact $sub1)))
  ;; CHECK-NEXT:  (local $sub2 (ref null (exact $sub2)))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $exact-gets
    (local $struct (ref null $struct))
    (local $sub1 (ref null (exact $sub1)))
    (local $sub2 (ref null (exact $sub2)))
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref $struct))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $sub1
        (i32.const 666)
        (i32.const 10)
        (i32.const 0)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $src (ref $struct)) (param $dst (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 2
  ;; CHECK-NEXT:   (local.get $dst)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $src)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $src (ref $struct)) (param $dst (ref $struct))
    ;; Copy from index 1 to index 2 in the same type. The copied value will
    ;; conflict with the initial value and inhibit optimization.
    (struct.set $struct 2
      (local.get $dst)
      (struct.get $struct 1
        (local.get $src)
      )
    )
  )

  ;; CHECK:      (func $get-0 (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get-0
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 0
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 0
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 0
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 0
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $get-1 (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get-1
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 1
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 1
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 1
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 1
        (local.get $sub2)
      )
    )
  )

  ;; CHECK:      (func $get-2 (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 2
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 2
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 2
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get-2
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 2
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 2
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 2
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 2
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $struct) (ref $struct))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; Same as above, except now field 2 is initialized with the same value as
    ;; field 1, so the copy will not do anything.
    (drop
      (struct.new $sub1
        (i32.const 666)
        (i32.const 10)
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $src (ref $struct)) (param $dst (ref $struct))
  ;; CHECK-NEXT:  (struct.set $struct 2
  ;; CHECK-NEXT:   (local.get $dst)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $src)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $src (ref $struct)) (param $dst (ref $struct))
    ;; Copy from index 1 to index 2 in the same type.
    (struct.set $struct 2
      (local.get $dst)
      (struct.get $struct 1
        (local.get $src)
      )
    )
  )

  ;; CHECK:      (func $get-2 (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $struct)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get-2
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 2
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 2
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 2
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 2
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $super (sub (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $super (sub (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $struct (sub $super (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $struct (sub $super (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub1 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub1 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
    ;; CHECK:       (type $sub2 (sub $struct (struct (field (mut i32)) (field (mut i32)) (field (mut i32)))))
    (type $sub2 (sub $struct (struct (field (mut i32) (mut i32) (mut i32)))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $sub1) (ref $sub1))))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $sub1
  ;; CHECK-NEXT:    (i32.const 666)
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    ;; We're back to initializing field 2 with a different value.
    (drop
      (struct.new $sub1
        (i32.const 666)
        (i32.const 10)
        (i32.const 0)
      )
    )
  )

  ;; CHECK:      (func $copy (type $5) (param $src (ref $sub1)) (param $dst (ref $sub1))
  ;; CHECK-NEXT:  (struct.set $sub1 2
  ;; CHECK-NEXT:   (local.get $dst)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $src)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $src (ref $sub1)) (param $dst (ref $sub1))
    ;; Copy from index 1 to index 2, but now on $sub1, so we will be able to
    ;; optimize $sub2.
    (struct.set $sub1 2
      (local.get $dst)
      (struct.get $sub1 1
        (local.get $src)
      )
    )
  )

  ;; CHECK:      (func $get-2 (type $4)
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $struct (ref null $struct))
  ;; CHECK-NEXT:  (local $sub1 (ref null $sub1))
  ;; CHECK-NEXT:  (local $sub2 (ref null $sub2))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $super 2
  ;; CHECK-NEXT:    (local.get $super)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $struct 2
  ;; CHECK-NEXT:    (local.get $struct)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $sub1 2
  ;; CHECK-NEXT:    (local.get $sub1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get-2
    (local $super (ref null $super))
    (local $struct (ref null $struct))
    (local $sub1 (ref null $sub1))
    (local $sub2 (ref null $sub2))
    (drop
      (struct.get $super 2
        (local.get $super)
      )
    )
    (drop
      (struct.get $struct 2
        (local.get $struct)
      )
    )
    (drop
      (struct.get $sub1 2
        (local.get $sub1)
      )
    )
    (drop
      (struct.get $sub2 2
        (local.get $sub2)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $3)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $B (ref null $B))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $B (ref null $B))
    (local $C (ref null $C))
    ;; Copy $A to $B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $B to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
  )

  ;; CHECK:      (func $get (type $4) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $3)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $B (ref null $B))
  ;; CHECK-NEXT:  (local $exact-B (ref null (exact $B)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $exact-B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $B (ref null $B))
    (local $exact-B (ref null (exact $B)))
    (local $C (ref null $C))
    ;; Copy $A to $B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy exact $B to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $exact-B)
      )
    )
  )

  ;; CHECK:      (func $get (type $4) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $3)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $B (ref null $B))
  ;; CHECK-NEXT:  (local $exact-B (ref null (exact $B)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $exact-B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $B (ref null $B))
    (local $exact-B (ref null (exact $B)))
    (local $C (ref null $C))
    ;; Copy $A to exact $B.
    (struct.set $B 0
      (local.get $exact-B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $B to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
  )

  ;; CHECK:      (func $get (type $4) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

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

  ;; CHECK:      (type $4 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $3)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $3)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $exact-B (ref null (exact $B)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $exact-B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $exact-B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $exact-B (ref null (exact $B)))
    (local $C (ref null $C))
    ;; Copy $A to exact $B.
    (struct.set $B 0
      (local.get $exact-B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $exact B to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $exact-B)
      )
    )
  )

  ;; CHECK:      (func $get (type $4) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $sub 0
  ;; CHECK-NEXT:   (local.get $sub)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $sub (ref null $sub))
    (local $super (ref null $super))
    (local $C (ref null $C))
    ;; Copy $A to $sub.
    (struct.set $sub 0
      (local.get $sub)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $super to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $super 0
        (local.get $super)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (local $exact-super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $sub 0
  ;; CHECK-NEXT:   (local.get $sub)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $sub (ref null $sub))
    (local $exact-super (ref null (exact $super)))
    (local $C (ref null $C))
    ;; Copy $A to $sub.
    (struct.set $sub 0
      (local.get $sub)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy exact $super to $C. This does not propagate the value.
    (struct.set $C 0
      (local.get $C)
      (struct.get $super 0
        (local.get $exact-super)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $exact-sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $sub 0
  ;; CHECK-NEXT:   (local.get $exact-sub)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $super)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $exact-sub (ref null (exact $sub)))
    (local $super (ref null $super))
    (local $C (ref null $C))
    ;; Copy $A to exact $sub.
    (struct.set $sub 0
      (local.get $exact-sub)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $super to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $super 0
        (local.get $super)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $exact-sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (local $exact-super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $sub 0
  ;; CHECK-NEXT:   (local.get $exact-sub)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-super)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $exact-sub (ref null (exact $sub)))
    (local $exact-super (ref null (exact $super)))
    (local $C (ref null $C))
    ;; Copy $A to exact $sub.
    (struct.set $sub 0
      (local.get $exact-sub)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy exact $super to $C. This does not propagate the value.
    (struct.set $C 0
      (local.get $C)
      (struct.get $super 0
        (local.get $exact-super)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $sub (ref null $sub))
    (local $super (ref null $super))
    (local $C (ref null $C))
    ;; Copy $A to $super.
    (struct.set $super 0
      (local.get $super)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $sub to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $exact-sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (local $super (ref null $super))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $exact-sub)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $exact-sub (ref null (exact $sub)))
    (local $super (ref null $super))
    (local $C (ref null $C))
    ;; Copy $A to $super.
    (struct.set $super 0
      (local.get $super)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy exact $sub to $C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $sub 0
        (local.get $exact-sub)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (ref.as_non_null
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 10)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $sub (ref null $sub))
  ;; CHECK-NEXT:  (local $exact-super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $exact-super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $sub (ref null $sub))
    (local $exact-super (ref null (exact $super)))
    (local $C (ref null $C))
    ;; Copy $A to exact $super.
    (struct.set $super 0
      (local.get $exact-super)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy $sub to $C. This does not propagate the value.
    (struct.set $C 0
      (local.get $C)
      (struct.get $sub 0
        (local.get $sub)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $super (sub (struct (field (mut i32)))))
    (type $super (sub (struct (field (mut i32)))))
    ;; CHECK:       (type $sub (sub $super (struct (field (mut i32)))))
    (type $sub (sub $super (struct (field (mut i32)))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $4 (func))

  ;; CHECK:      (type $5 (func (param (ref $C)) (result i32)))

  ;; CHECK:      (func $init (type $4)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.new $A
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init
    (drop
      (struct.new $A
        (i32.const 10)
      )
    )
  )

  ;; CHECK:      (func $copy (type $4)
  ;; CHECK-NEXT:  (local $A (ref null $A))
  ;; CHECK-NEXT:  (local $exact-sub (ref null (exact $sub)))
  ;; CHECK-NEXT:  (local $exact-super (ref null (exact $super)))
  ;; CHECK-NEXT:  (local $C (ref null $C))
  ;; CHECK-NEXT:  (struct.set $super 0
  ;; CHECK-NEXT:   (local.get $exact-super)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $exact-sub)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy
    (local $A (ref null $A))
    (local $exact-sub (ref null (exact $sub)))
    (local $exact-super (ref null (exact $super)))
    (local $C (ref null $C))
    ;; Copy $A to exact $super.
    (struct.set $super 0
      (local.get $exact-super)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy exact $sub to $C. This does not propagate the value.
    (struct.set $C 0
      (local.get $C)
      (struct.get $sub 0
        (local.get $exact-sub)
      )
    )
  )

  ;; CHECK:      (func $get (type $5) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $get (param $C (ref $C)) (result i32)
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 511)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i32 to i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i8.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i16))))
    (type $B (struct (field (mut i16))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 131071)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 131071)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 65535)
  ;; CHECK-NEXT:    (i32.const 65535)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x0001FFFF)
    )
    ;; Copy i32 to i16.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i16.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 511)
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 255)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i32.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i32.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 511)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const -1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i32 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read truncated then sign extended i32.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i16))))
    (type $B (struct (field (mut i16))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 511)
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 65535)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i16.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i16.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i16))))
    (type $B (struct (field (mut i16))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 511)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 65535)
  ;; CHECK-NEXT:    (i32.const 65535)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i16 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read truncated then sign extended i16.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i16))))
    (type $A (struct (field (mut i16))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 131071)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 131071)
  ;; CHECK-NEXT:     (i32.const 65535)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 65535)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x0001FFFF)
    )
    ;; Copy i16 to i32.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i32.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i16))))
    (type $A (struct (field (mut i16))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 131071)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 131071)
  ;; CHECK-NEXT:      (i32.const 16)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 16)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const -1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x0001FFFF)
    )
    ;; Copy i16 to i32 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read truncated then sign extended i32.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i16))))
    (type $A (struct (field (mut i16))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 131071)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 131071)
  ;; CHECK-NEXT:     (i32.const 65535)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x0001FFFF)
    )
    ;; Copy i16 to i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i8.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i16))))
    (type $A (struct (field (mut i16))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 131071)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 131071)
  ;; CHECK-NEXT:      (i32.const 16)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 16)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x0001FFFF)
    )
    ;; Copy i16 to i8 with sign extension. This does not make a difference.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i8.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
  )

  ;; CHECK:      (type $1 (func (param (ref $A)) (result i32)))

  ;; CHECK:      (func $test (type $1) (param $A (ref $A)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const -1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (struct.get_u $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get_u $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0xFFFFFFFF)
    )
    ;; Copy the i8 to itself.
    (struct.set $A 0
      (local.get $A)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i8.
    ;; TODO: We do not optimize this because the truncated copy value conflicts
    ;; with the untruncated value found by the initial analysis. Fix this by
    ;; tracking truncations and sign extensions as part of the analysis.
    (struct.get $A 0
      (local.get $A)
    )
  )
)

(module
  (rec
    ;; CHECK:      (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
  )

  ;; CHECK:      (type $1 (func (param (ref $A)) (result i32)))

  ;; CHECK:      (func $test (type $1) (param $A (ref $A)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const -1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const -1)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const -1)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0xFFFFFFFF)
    )
    ;; Copy the i8 to itself with sign extension.
    (struct.set $A 0
      (local.get $A)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read truncated i8. Now we can optimize because the sign-extended value
    ;; happens to match the original value.
    (struct.get $A 0
      (local.get $A)
    )
  )
)

(module
  (rec
    ;; CHECK:      (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
  )

  ;; CHECK:      (type $1 (func (param (ref $A)) (result i32)))

  ;; CHECK:      (func $test (type $1) (param $A (ref $A)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (struct.get_s $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get_u $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy the i8 to itself with sign extension.
    (struct.set $A 0
      (local.get $A)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Now the value does not match and we don't optimize, even though we could
    ;; in principle.
    (struct.get $A 0
      (local.get $A)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (global $g i32 (i32.const 0))
  (global $g i32 (i32.const 0))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (global.get $g)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (global.get $g)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get_u $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (global.get $g)
    )
    ;; Copy the i32 with global to the i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Read the i8. We do not optimize this because we cannot model the
    ;; truncation of the global. TODO.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (global $g i32 (i32.const 0))
  (global $g i32 (i32.const 0))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (global.get $g)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (global.get $g)
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (global.get $g)
    )
    ;; Copy the i8 with global to the i32.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read the i32. We still cannot optimize. TODO.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (global $g i32 (i32.const 0))
  (global $g i32 (i32.const 0))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (global.get $g)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (global.get $g)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (global.get $g)
    )
    ;; Copy the i8 with global to the i32 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read the i32. We still cannot optimize. TODO.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
  )

  ;; CHECK:      (type $1 (func (param (ref $A)) (result i32)))

  ;; CHECK:      (global $g i32 (i32.const 0))
  (global $g i32 (i32.const 0))

  ;; CHECK:      (func $test (type $1) (param $A (ref $A)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (global.get $g)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (struct.get_u $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get_u $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (global.get $g)
    )
    ;; Copy the i8 holding the global to itself.
    (struct.set $A 0
      (local.get $A)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read the i8. We cannot model the truncated global. TODO.
    (struct.get_u $A 0
      (local.get $A)
    )
  )
)


(module
  (rec
    ;; CHECK:      (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
  )

  ;; CHECK:      (type $1 (func (param (ref $A)) (result i32)))

  ;; CHECK:      (global $g i32 (i32.const 0))
  (global $g i32 (i32.const 0))

  ;; CHECK:      (func $test (type $1) (param $A (ref $A)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (global.get $g)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (struct.get_s $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get_u $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (global.get $g)
    )
    ;; Copy the i8 holding the global to itself with sign extension.
    (struct.set $A 0
      (local.get $A)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read the i8. We cannot model the truncated global. TODO.
    (struct.get_u $A 0
      (local.get $A)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; Copy the uninitialized i8 to i32.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Read the i32. It should still be uninitialized and optimized out.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; Copy the uninitialized i8 to i32 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Read the i32. It should still be uninitialized and optimized out.
    (struct.get $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
  )

  ;; CHECK:      (type $2 (func (param (ref $A) (ref $B)) (result i32)))

  ;; CHECK:      (func $test (type $2) (param $A (ref $A)) (param $B (ref $B)) (result i32)
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (result i32)
    ;; Copy the uninitialized i32 to i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Read the i8. It should still be uninitialized and optimized out.
    (struct.get_u $B 0
      (local.get $B)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 511)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 255)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i32 to i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy the i8 to another i32.
    (struct.set $C 0
      (local.get $C)
      (struct.get_u $B 0
        (local.get $B)
      )
    )
    ;; Read truncated i32.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i8))))
    (type $B (struct (field (mut i8))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 511)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 255)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const -1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i32 to i8.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy the i8 to another i32 with sign extension.
    (struct.set $C 0
      (local.get $C)
      (struct.get_s $B 0
        (local.get $B)
      )
    )
    ;; Read truncated i32.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i8))))
    (type $C (struct (field (mut i8))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.and
  ;; CHECK-NEXT:     (i32.const 511)
  ;; CHECK-NEXT:     (i32.const 255)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i32.
    (struct.set $B 0
      (local.get $B)
      (struct.get_u $A 0
        (local.get $A)
      )
    )
    ;; Copy the i32 to another i8.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Read the i8.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i8))))
    (type $A (struct (field (mut i8))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i8))))
    (type $C (struct (field (mut i8))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 511)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.shr_s
  ;; CHECK-NEXT:     (i32.shl
  ;; CHECK-NEXT:      (i32.const 511)
  ;; CHECK-NEXT:      (i32.const 24)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 24)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const -1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.and
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:    (i32.const 255)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    (struct.set $A 0
      (local.get $A)
      (i32.const 0x000001FF)
    )
    ;; Copy i8 to i32 with sign extension.
    (struct.set $B 0
      (local.get $B)
      (struct.get_s $A 0
        (local.get $A)
      )
    )
    ;; Copy the i32 to another i8.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Read the i8.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (ref.as_non_null
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    ;; A and B separately copy matching values into C
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    (struct.set $B 0
      (local.get $B)
      (i32.const 10)
    )
    ;; Copy A to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy B to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Read C.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C)) (result i32)))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C)) (result i32)
    ;; Now A and B separately copy different values into C
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    (struct.set $B 0
      (local.get $B)
      (i32.const 20)
    )
    ;; Copy A to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy B to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Read C. We cannot optimize because there are multiple values.
    (struct.get $C 0
      (local.get $C)
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C))))

  ;; CHECK:      (func $test (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $C)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $test (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; Copy A to both B and C.
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    ;; Copy A to B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy A to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Read B. We can optimize.
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Read C. We can optimize this, too.
    (drop
      (struct.get $C 0
        (local.get $C)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C))))

  ;; CHECK:      (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; Create a loop copying A -> B -> C -> A.
    ;; Copy A to B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy B to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Copy C to A.
    (struct.set $A 0
      (local.get $A)
      (struct.get $C 0
        (local.get $C)
      )
    )
  )

  ;; CHECK:      (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $A)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $B)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $C)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; Since no value ever entered the loop, these all get optimized out.
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
    (drop
      (struct.get $C 0
        (local.get $C)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C))))

  ;; CHECK:      (type $4 (func (param (ref $A))))

  ;; CHECK:      (func $init (type $4) (param $A (ref $A))
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $A (ref $A))
    ;; Now we inject a value into the loop.
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
  )

  ;; CHECK:      (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $C)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; Create a loop copying A -> B -> C -> A.
    ;; Copy A to B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy B to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Copy C to A.
    (struct.set $A 0
      (local.get $A)
      (struct.get $C 0
        (local.get $C)
      )
    )
  )

  ;; CHECK:      (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $A)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $B)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (ref.as_non_null
  ;; CHECK-NEXT:      (local.get $C)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; These all get optimized to the one injected value.
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
    (drop
      (struct.get $C 0
        (local.get $C)
      )
    )
  )
)

(module
  (rec
    ;; CHECK:      (rec
    ;; CHECK-NEXT:  (type $A (struct (field (mut i32))))
    (type $A (struct (field (mut i32))))
    ;; CHECK:       (type $B (struct (field (mut i32))))
    (type $B (struct (field (mut i32))))
    ;; CHECK:       (type $C (struct (field (mut i32))))
    (type $C (struct (field (mut i32))))
  )

  ;; CHECK:      (type $3 (func (param (ref $A) (ref $B) (ref $C))))

  ;; CHECK:      (type $4 (func (param (ref $A) (ref $C))))

  ;; CHECK:      (func $init (type $4) (param $A (ref $A)) (param $C (ref $C))
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $init (param $A (ref $A)) (param $C (ref $C))
    ;; Now we inject two different values into the loop in different places. We
    ;; won't be able to optimize anything.
    (struct.set $A 0
      (local.get $A)
      (i32.const 10)
    )
    (struct.set $C 0
      (local.get $C)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $copy (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (struct.set $B 0
  ;; CHECK-NEXT:   (local.get $B)
  ;; CHECK-NEXT:   (struct.get $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $C 0
  ;; CHECK-NEXT:   (local.get $C)
  ;; CHECK-NEXT:   (struct.get $B 0
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $A 0
  ;; CHECK-NEXT:   (local.get $A)
  ;; CHECK-NEXT:   (struct.get $C 0
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $copy (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; Create a loop copying A -> B -> C -> A.
    ;; Copy A to B.
    (struct.set $B 0
      (local.get $B)
      (struct.get $A 0
        (local.get $A)
      )
    )
    ;; Copy B to C.
    (struct.set $C 0
      (local.get $C)
      (struct.get $B 0
        (local.get $B)
      )
    )
    ;; Copy C to A.
    (struct.set $A 0
      (local.get $A)
      (struct.get $C 0
        (local.get $C)
      )
    )
  )

  ;; CHECK:      (func $get (type $3) (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $A 0
  ;; CHECK-NEXT:    (local.get $A)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $B 0
  ;; CHECK-NEXT:    (local.get $B)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $C 0
  ;; CHECK-NEXT:    (local.get $C)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $get (param $A (ref $A)) (param $B (ref $B)) (param $C (ref $C))
    ;; These cannot be optimized.
    (drop
      (struct.get $A 0
        (local.get $A)
      )
    )
    (drop
      (struct.get $B 0
        (local.get $B)
      )
    )
    (drop
      (struct.get $C 0
        (local.get $C)
      )
    )
  )
)
