;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-ctor-eval --ctors=test --kept-exports=test --quiet -all -S -o - | filecheck %s

(module
 ;; CHECK:      (type $A (struct (field (mut (ref null $A))) (field i32)))
 (type $A (struct (field (mut (ref null $A))) (field i32)))

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

 ;; CHECK:      (type $2 (func (result i32)))

 ;; CHECK:      (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_3))
 (global $a (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  ;; This generates a self-cycle where the global $a's ref field points to
  ;; itself. To handle this, wasm-ctor-eval will emit a new global with a null
  ;; in the ref field, and add a start function that adds the self-reference.
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $a)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $2) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (struct.get $A 0
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  ;; Getting $A.0.1 (reading from the reference in the global's first field)
  ;; checks that we have a proper reference there. If we could do --fuzz-exec
  ;; here we could validate that (but atm we can't use --output=fuzz-exec at the
  ;; same time as --all-items in the update_lit_checks.py note).
  (struct.get $A 1
   (struct.get $A 0
    (global.get $a)
   )
  )
 )
)

;; CHECK:      (func $start (type $1)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_3)
;; CHECK-NEXT:   (global.get $ctor-eval$global_3)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; As above, but with $A's fields reversed. This verifies we use the right
 ;; field index in the start function.

 ;; CHECK:      (type $A (struct (field i32) (field (mut (ref null $A)))))
 (type $A (struct (field i32) (field (mut (ref null $A)))))

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

 ;; CHECK:      (type $2 (func (result i32)))

 ;; CHECK:      (global $ctor-eval$global_3 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_3))
 (global $a (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (i32.const 42)
     (ref.null $A)
    )
   )
  )
  (struct.set $A 1
   (local.get $a)
   (local.get $a)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $2) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 0
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 0
   (struct.get $A 1
    (global.get $a)
   )
  )
 )
)

;; CHECK:      (func $start (type $1)
;; CHECK-NEXT:  (struct.set $A 1
;; CHECK-NEXT:   (global.get $ctor-eval$global_3)
;; CHECK-NEXT:   (global.get $ctor-eval$global_3)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; A cycle between two globals.

 ;; CHECK:      (type $A (struct (field (mut (ref null $A))) (field i32)))
 (type $A (struct (field (mut (ref null $A))) (field i32)))

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

 ;; CHECK:      (type $2 (func (result i32)))

 ;; CHECK:      (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_8 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_7)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7))
 (global $a (mut (ref null $A)) (ref.null $A))

 ;; CHECK:      (global $b (mut (ref null $A)) (global.get $ctor-eval$global_8))
 (global $b (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $A))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $A
     (global.get $a)  ;; $b can refer to $a since we've created $a already.
     (i32.const 1337)
    )
   )
  )
  ;; $a needs a set to allow us to create the cycle.
  (struct.set $A 0
   (local.get $a)
   (local.get $b)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $2) (result i32)
 ;; CHECK-NEXT:  (i32.add
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $b)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (i32.add
   (struct.get $A 1
    (global.get $a)
   )
   (struct.get $A 1
    (global.get $b)
   )
  )
 )
)

;; CHECK:      (func $start (type $1)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_7)
;; CHECK-NEXT:   (global.get $ctor-eval$global_8)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; A cycle between two globals of different types. One of them has an
 ;; immutable field in the cycle.

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

  ;; CHECK:       (type $B (struct (field (ref null $A)) (field i32)))
  (type $B (struct (field (ref null $A)) (field i32)))
 )

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

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

 ;; CHECK:      (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_7)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7))
 (global $a (mut (ref null $A)) (ref.null $A))

 ;; CHECK:      (global $b (mut (ref null $B)) (global.get $ctor-eval$global_8))
 (global $b (mut (ref null $B)) (ref.null $B))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $B
     (global.get $a)
     (i32.const 1337)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $b)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result i32)
 ;; CHECK-NEXT:  (i32.add
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (struct.get $B 1
 ;; CHECK-NEXT:    (global.get $b)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (i32.add
   (struct.get $A 1
    (global.get $a)
   )
   (struct.get $B 1
    (global.get $b)
   )
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_7)
;; CHECK-NEXT:   (global.get $ctor-eval$global_8)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; As above, but with the order of globals reversed.

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

  ;; CHECK:       (type $B (struct (field (ref null $A)) (field i32)))
  (type $B (struct (field (ref null $A)) (field i32)))
 )


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

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

 ;; CHECK:      (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_7)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7))

 ;; CHECK:      (global $b (mut (ref null $B)) (global.get $ctor-eval$global_8))
 (global $b (mut (ref null $B)) (ref.null $B))

 (global $a (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $B
     (global.get $a)
     (i32.const 1337)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $b)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result i32)
 ;; CHECK-NEXT:  (i32.add
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (struct.get $B 1
 ;; CHECK-NEXT:    (global.get $b)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (i32.add
   (struct.get $A 1
    (global.get $a)
   )
   (struct.get $B 1
    (global.get $b)
   )
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_7)
;; CHECK-NEXT:   (global.get $ctor-eval$global_8)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
  ;; A cycle as above, but with non-nullability rather than immutability.

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

  ;; CHECK:       (type $B (struct (field (mut (ref $A))) (field i32)))
  (type $B (struct (field (mut (ref $A))) (field i32)))
 )

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

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

 ;; CHECK:      (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_7)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7))
 (global $a (mut (ref null $A)) (ref.null $A))

 (global $b (mut (ref null $B)) (ref.null $B))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $B
     (local.get $a)
     (i32.const 1337)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $b)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_7)
;; CHECK-NEXT:   (global.get $ctor-eval$global_8)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
  ;; A cycle as above, but with globals in reverse order and with both non-
  ;; nullability and immutability.

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

  ;; CHECK:       (type $B (struct (field (ref $A)) (field i32)))
  (type $B (struct (field (ref $A)) (field i32)))
 )


 (global $b (mut (ref null $B)) (ref.null $B))

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

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

 ;; CHECK:      (global $ctor-eval$global_7 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_8 (ref (exact $B)) (struct.new $B
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_7)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_7))
 (global $a (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $B
     (local.get $a)
     (i32.const 1337)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $b)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_7)
;; CHECK-NEXT:   (global.get $ctor-eval$global_8)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; A cycle between three globals.

 ;; CHECK:      (type $A (struct (field (mut (ref null $A))) (field i32)))
 (type $A (struct (field (mut (ref null $A))) (field i32)))

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

 ;; CHECK:      (type $2 (func (result i32)))

 ;; CHECK:      (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (i32.const 1337)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_13 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_14)
 ;; CHECK-NEXT:  (i32.const 99999)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12))
 (global $a (mut (ref null $A)) (ref.null $A))

 (global $b (mut (ref null $A)) (ref.null $A))

 (global $c (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $A))
  (local $c (ref $A))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (struct.new $A
     (global.get $a)
     (i32.const 1337)
    )
   )
  )
  (global.set $c
   (local.tee $c
    (struct.new $A
     (global.get $b)
     (i32.const 99999)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $c)
  )
 )

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $2) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $1)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_12)
;; CHECK-NEXT:   (global.get $ctor-eval$global_13)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $A))
;; CHECK-NEXT:  (local $c (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; A cycle between three globals as above, but now using different types and
 ;; also both structs and arrays. Also reverse the order of globals, make
 ;; one array immutable and one non-nullable, and make one array refer to the
 ;; other two.

 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $A (struct (field (mut (ref null $C))) (field i32)))
  (type $A (struct (field (mut (ref null $C))) (field i32)))
  ;; CHECK:       (type $B (array (ref null $A)))
  (type $B (array (ref null $A)))
  ;; CHECK:       (type $C (array (mut (ref any))))
  (type $C (array (mut (ref any))))
 )

 (global $c (mut (ref null $C)) (ref.null $C))

 (global $b (mut (ref null $B)) (ref.null $B))

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

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

 ;; CHECK:      (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12))
 (global $a (mut (ref null $A)) (ref.null $A))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (local $c (ref $C))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $C)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (array.new $B
     (global.get $a)
     (i32.const 10)
    )
   )
  )
  (global.set $c
   (local.tee $c
    (array.new_fixed $C 2
     (local.get $b)
     (local.get $a)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (global.get $c)
  )
 )

 ;; CHECK:      (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_14)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $4) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $3)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_12)
;; CHECK-NEXT:   (global.get $ctor-eval$global_13)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $3)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (local $c (ref $C))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; As above but with the order of globals reversed once more.

 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $A (struct (field (mut (ref null $C))) (field i32)))
  (type $A (struct (field (mut (ref null $C))) (field i32)))
  ;; CHECK:       (type $B (array (ref null $A)))
  (type $B (array (ref null $A)))
  ;; CHECK:       (type $C (array (mut (ref any))))
  (type $C (array (mut (ref any))))
 )

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

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

 ;; CHECK:      (global $ctor-eval$global_12 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 10
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_12))
 (global $a (mut (ref null $A)) (ref.null $A))

 (global $b (mut (ref null $B)) (ref.null $B))

 (global $c (mut (ref null $C)) (ref.null $C))

 (func $test (export "test")
  (local $a (ref $A))
  (local $b (ref $B))
  (local $c (ref $C))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $C)
     (i32.const 42)
    )
   )
  )
  (global.set $b
   (local.tee $b
    (array.new $B
     (global.get $a)
     (i32.const 10)
    )
   )
  )
  (global.set $c
   (local.tee $c
    (array.new_fixed $C 2
     (local.get $b)
     (local.get $a)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (global.get $c)
  )
 )

 ;; CHECK:      (global $ctor-eval$global_13 (ref (exact $C)) (array.new_fixed $C 2
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_14)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_12)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $4) (result i32)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $3)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_12)
;; CHECK-NEXT:   (global.get $ctor-eval$global_13)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $3)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (local $c (ref $C))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; A cycle between two globals, where some of the fields participate in the
 ;; cycle and some do not.

 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $A (struct (field (mut (ref null $B))) (field (mut (ref null $B))) (field (mut (ref null $B)))))
  (type $A (struct (field (mut (ref null $B))) (field (mut (ref null $B))) (field (mut (ref null $B)))))
  ;; CHECK:       (type $B (array (ref null $A)))
  (type $B (array (ref null $A)))
 )

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

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

 ;; CHECK:      (global $ctor-eval$global_17 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_14 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_18 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_14))
 (global $a (mut (ref null $A)) (ref.null $A))
 (global $b (mut (ref null $B)) (ref.null $B))

 (func $test (export "test")
  (local $a (ref $A))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (array.new_default $B
      (i32.const 0)
     )
     (ref.null $B)
     (array.new_default $B
      (i32.const 0)
     )
    )
   )
  )
  (global.set $b
   (array.new_fixed $B 3
    (struct.new_default $A)
    (global.get $a)
    (struct.new_default $A)
   )
  )
  (struct.set $A 1
   (local.get $a)
   (global.get $b)
  )
 )

 ;; CHECK:      (global $ctor-eval$global_16 (ref (exact $B)) (array.new_fixed $B 3
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_17)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_14)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_18)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_15 (ref (exact $B)) (array.new_fixed $B 0))

 ;; CHECK:      (global $ctor-eval$global_19 (ref (exact $B)) (array.new_fixed $B 0))

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result anyref)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result (ref null any))
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (global.get $ctor-eval$global_15)
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (struct.set $A 1
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (global.get $ctor-eval$global_16)
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (struct.set $A 2
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (global.get $ctor-eval$global_19)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; As above, with the cycle creation logic reversed.

 (rec
  ;; CHECK:      (rec
  ;; CHECK-NEXT:  (type $A (struct (field (ref null $B)) (field (ref null $B)) (field (ref null $B))))
  (type $A (struct (field (ref null $B)) (field (ref null $B)) (field (ref null $B))))
  ;; CHECK:       (type $B (array (mut (ref null $A))))
  (type $B (array (mut (ref null $A))))
 )

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

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

 ;; CHECK:      (global $ctor-eval$global_17 (ref (exact $B)) (array.new_fixed $B 0))

 ;; CHECK:      (global $ctor-eval$global_14 (ref (exact $B)) (array.new_fixed $B 3
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_18 (ref (exact $B)) (array.new_fixed $B 0))

 ;; CHECK:      (global $ctor-eval$global_16 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_17)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_14)
 ;; CHECK-NEXT:  (global.get $ctor-eval$global_18)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_16))
 (global $a (mut (ref null $A)) (ref.null $A))
 (global $b (mut (ref null $B)) (ref.null $B))

 (func $test (export "test")
  (local $b (ref $B))
  (global.set $b
   (local.tee $b
    (array.new_fixed $B 3
     (struct.new_default $A)
     (ref.null $A)
     (struct.new_default $A)
    )
   )
  )
  (global.set $a
   (struct.new $A
    (array.new_default $B
     (i32.const 0)
    )
    (global.get $b)
    (array.new_default $B
     (i32.const 0)
    )
   )
  )
  (array.set $B
   (local.get $b)
   (i32.const 1)
   (global.get $a)
  )
 )

 ;; CHECK:      (global $ctor-eval$global_15 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $ctor-eval$global_19 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)

 ;; CHECK:      (func $keepalive (type $3) (result anyref)
 ;; CHECK-NEXT:  (struct.get $A 1
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result (ref null any))
  (struct.get $A 1
   (global.get $a)
  )
 )
)

;; CHECK:      (func $start (type $2)
;; CHECK-NEXT:  (array.set $B
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (i32.const 0)
;; CHECK-NEXT:   (global.get $ctor-eval$global_15)
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (array.set $B
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (i32.const 1)
;; CHECK-NEXT:   (global.get $ctor-eval$global_16)
;; CHECK-NEXT:  )
;; CHECK-NEXT:  (array.set $B
;; CHECK-NEXT:   (global.get $ctor-eval$global_14)
;; CHECK-NEXT:   (i32.const 2)
;; CHECK-NEXT:   (global.get $ctor-eval$global_19)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $2)
;; CHECK-NEXT:  (local $b (ref $B))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; The start function already exists here. We must prepend to it.

 ;; CHECK:      (type $A (struct (field (mut (ref null $A))) (field i32)))
 (type $A (struct (field (mut (ref null $A))) (field i32)))

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

 ;; CHECK:      (type $2 (func (result i32)))

 ;; CHECK:      (global $ctor-eval$global_4 (ref (exact $A)) (struct.new $A
 ;; CHECK-NEXT:  (ref.null none)
 ;; CHECK-NEXT:  (i32.const 42)
 ;; CHECK-NEXT: ))

 ;; CHECK:      (global $a (mut (ref null $A)) (global.get $ctor-eval$global_4))
 (global $a (mut (ref null $A)) (ref.null $A))

 ;; CHECK:      (global $b (mut (ref null $A)) (ref.null none))
 (global $b (mut (ref null $A)) (ref.null $A))

 ;; CHECK:      (export "test" (func $test_3))

 ;; CHECK:      (export "keepalive" (func $keepalive))

 ;; CHECK:      (start $start)
 (start $start)

 (func $test (export "test")
  (local $a (ref $A))
  (global.set $a
   (local.tee $a
    (struct.new $A
     (ref.null $A)
     (i32.const 42)
    )
   )
  )
  (struct.set $A 0
   (local.get $a)
   (local.get $a)
  )
 )

 ;; CHECK:      (func $keepalive (type $2) (result i32)
 ;; CHECK-NEXT:  (i32.add
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $a)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:   (struct.get $A 1
 ;; CHECK-NEXT:    (global.get $b)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $keepalive (export "keepalive") (result i32)
  (i32.add
   (struct.get $A 1
    (global.get $a)
   )
   (struct.get $A 1
    (global.get $b)
   )
  )
 )

 ;; CHECK:      (func $start (type $1)
 ;; CHECK-NEXT:  (struct.set $A 0
 ;; CHECK-NEXT:   (global.get $ctor-eval$global_4)
 ;; CHECK-NEXT:   (global.get $ctor-eval$global_4)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (global.set $b
 ;; CHECK-NEXT:   (global.get $a)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $start
  (global.set $b
   (global.get $a)
  )
 )
)

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (local $a (ref $A))
;; CHECK-NEXT:  (nop)
;; CHECK-NEXT: )
(module
 ;; CHECK:      (type $A (struct (field (mut (ref null $A)))))
 (type $A (struct (field (mut (ref null $A)))))

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

 ;; CHECK:      (type $2 (func (param anyref)))

 ;; CHECK:      (import "a" "b" (func $import (type $2) (param anyref)))
 (import "a" "b" (func $import (param anyref)))

 (func $test (export "test")
  (local $a (ref $A))
  (struct.set $A 0
   (local.tee $a
    (struct.new_default $A)
   )
   (local.get $a)
  )
  ;; The previous instructions created a cycle, which we now send to an import.
  ;; The import will block us from evalling the entire function, and we will
  ;; only partially eval it, removing the statements before the call. Note that
  ;; the cycle only exists in local state - there is no global it is copied to -
  ;; and so this test verifies that we handle cycles in local state.
  (call $import
   (local.get $a)
  )
 )
)
;; CHECK:      (global $ctor-eval$global (ref (exact $A)) (struct.new $A
;; CHECK-NEXT:  (ref.null none)
;; CHECK-NEXT: ))

;; CHECK:      (export "test" (func $test_3))

;; CHECK:      (start $start)

;; CHECK:      (func $start (type $1)
;; CHECK-NEXT:  (struct.set $A 0
;; CHECK-NEXT:   (global.get $ctor-eval$global)
;; CHECK-NEXT:   (global.get $ctor-eval$global)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )

;; CHECK:      (func $test_3 (type $1)
;; CHECK-NEXT:  (call $import
;; CHECK-NEXT:   (global.get $ctor-eval$global)
;; CHECK-NEXT:  )
;; CHECK-NEXT: )
(module
 ;; A circular reference using a non-nullable (but mutable) field. Unlike cases
 ;; above, we cannot break up such cycles, and must give up. We should at least
 ;; not error.

 ;; CHECK:      (type $array (array i8))
 (type $array  (array i8))
 ;; CHECK:      (type $struct (struct (field (mut (ref any)))))
 (type $struct (struct (field (mut (ref any)))))

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

 ;; CHECK:      (global $global (mut i32) (i32.const 42))
 (global $global (mut i32) (i32.const 42))

 ;; CHECK:      (export "test" (func $test))

 ;; CHECK:      (func $test (type $2)
 ;; CHECK-NEXT:  (local $temp (ref $struct))
 ;; CHECK-NEXT:  (global.set $global
 ;; CHECK-NEXT:   (i32.const 1337)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.set $temp
 ;; CHECK-NEXT:   (struct.new $struct
 ;; CHECK-NEXT:    (array.new_fixed $array 0)
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (struct.set $struct 0
 ;; CHECK-NEXT:   (local.get $temp)
 ;; CHECK-NEXT:   (local.get $temp)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $test (export "test")
  (local $temp (ref $struct))

  ;; Set the global. This will not get written out, as we will cancel all our
  ;; work when we hit the cycle below. (TODO: improve that)
  (global.set $global
   (i32.const 1337)
  )

  ;; Start with the struct referring to an array.
  (local.set $temp
   (struct.new $struct
    (array.new_fixed $array 0)
   )
  )

  ;; Make the struct refer to itself, circularly.
  (struct.set $struct 0
   (local.get $temp)
   (local.get $temp)
  )
 )
)

