;; 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 --unsubtyping --remove-unused-types -all -S -o - | filecheck %s
(module
;; $sub1 and $sub2 should become parent types and $super should be removed.
(type $super (sub (struct)))
;; CHECK: (rec
;; CHECK-NEXT: (type $sub2 (sub (struct (field f32))))
;; CHECK: (type $sub1 (sub (struct (field i32))))
(type $sub1 (sub $super (struct i32)))
(type $sub2 (sub $super (struct f32)))
;; CHECK: (global $sub1 (ref $sub1) (struct.new_default $sub1))
(global $sub1 (ref $sub1) (struct.new_default $sub1))
;; CHECK: (global $sub2 (ref $sub2) (struct.new_default $sub2))
(global $sub2 (ref $sub2) (struct.new_default $sub2))
)
(module
;; Same result, but we start with $sub2 <: $sub1.
(type $super (sub (struct)))
;; CHECK: (rec
;; CHECK-NEXT: (type $sub2 (sub (struct (field i32) (field i32))))
;; CHECK: (type $sub1 (sub (struct (field i32))))
(type $sub1 (sub $super (struct i32)))
(type $sub2 (sub $sub1 (struct i32 i32)))
;; CHECK: (global $sub1 (ref $sub1) (struct.new_default $sub1))
(global $sub1 (ref $sub1) (struct.new_default $sub1))
;; CHECK: (global $sub2 (ref $sub2) (struct.new_default $sub2))
(global $sub2 (ref $sub2) (struct.new_default $sub2))
)
(module
;; CHECK: (type $super (sub (func)))
(type $super (sub (func)))
;; CHECK: (type $sub (sub $super (func)))
(type $sub (sub $super (func)))
;; Public types should not be changed.
;; CHECK: (export "super" (func $super))
;; CHECK: (export "sub" (func $sub))
;; CHECK: (func $super (type $super)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $super (export "super") (type $super)
(unreachable)
)
;; CHECK: (func $sub (type $sub)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $sub (export "sub") (type $sub)
(unreachable)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; A function body requires subtyping
;; CHECK: (type $2 (func (result (ref $super))))
;; CHECK: (func $foo (type $2) (result (ref $super))
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
(func $foo (result (ref $super))
(struct.new $sub)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; A global initializer requires subtyping
;; CHECK: (global $g1 (ref $super) (struct.new_default $sub))
(global $g1 (ref $super) (struct.new $sub))
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $subsub (sub $sub (struct )))
(type $subsub (sub $sub (struct)))
;; CHECK: (table $t 1 1 (ref null $super))
(table $t 1 1 (ref null $super))
;; An active element segment requires subtyping. So does an element segment
;; element.
;; CHECK: (elem $e (table $t) (i32.const 0) (ref null $sub) (struct.new_default $subsub))
(elem $e (table $t) (offset (i32.const 0)) (ref null $sub) (struct.new $subsub))
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $X (sub (struct )))
(type $X (sub (struct)))
;; CHECK: (type $Y (sub $X (struct )))
(type $Y (sub $X (struct)))
;; CHECK: (type $A (sub (struct (field (ref null $X)))))
(type $A (sub (struct (ref null $X))))
;; CHECK: (type $B (sub $A (struct (field (ref null $Y)))))
(type $B (sub $A (struct (ref null $Y))))
;; Requiring B <: A also requires X <: Y
;; CHECK: (global $g (ref $A) (struct.new_default $B))
(global $g (ref $A) (struct.new_default $B))
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $X (sub (struct )))
(type $X (sub (struct)))
;; CHECK: (type $Y (sub $X (struct )))
(type $Y (sub $X (struct)))
;; CHECK: (type $A (sub (array (ref null $X))))
(type $A (sub (array (field (ref null $X)))))
;; CHECK: (type $B (sub $A (array (ref null $Y))))
(type $B (sub $A (array (field (ref null $Y)))))
;; Transitive dependencies through an array.
;; CHECK: (global $g (ref $A) (array.new_default $B
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: ))
(global $g (ref $A) (array.new_default $B (i32.const 0)))
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $X (sub (struct )))
(type $X (sub (struct)))
;; CHECK: (type $Y (sub $X (struct )))
(type $Y (sub $X (struct)))
;; CHECK: (type $X' (sub (struct )))
(type $X' (sub (struct)))
;; CHECK: (type $Y' (sub $X' (struct )))
(type $Y' (sub $X' (struct)))
;; CHECK: (type $A (sub (func (param (ref $Y')) (result (ref $X)))))
(type $A (sub (func (param (ref $Y')) (result (ref $X)))))
;; CHECK: (type $B (sub $A (func (param (ref $X')) (result (ref $Y)))))
(type $B (sub $A (func (param (ref $X')) (result (ref $Y)))))
)
;; Transitive dependencies through a function type.
;; CHECK: (global $g (ref null $A) (ref.func $foo))
(global $g (ref null $A) (ref.func $foo))
;; CHECK: (func $foo (type $B) (param $0 (ref $X')) (result (ref $Y))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $foo (type $B)
(unreachable)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $block-fallthrough (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_if $l
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $block-fallthrough
(drop
(block $l (result (ref $super))
(drop
(br_if $l
(struct.new $super)
(i32.const 0)
)
)
;; This requires $sub <: $super
(struct.new $sub)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $opt (sub (struct (field i32))))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $opt (sub $super (struct i32)))
;; CHECK: (type $3 (func))
;; CHECK: (func $block-br (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref $super))
;; CHECK-NEXT: (br $l
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $other (result (ref $opt))
;; CHECK-NEXT: (br $other
;; CHECK-NEXT: (struct.new_default $opt)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $block-br
(drop
(block $l (result (ref $super))
(br $l
;; This requires $sub <: $super
(struct.new $sub)
)
(drop
(block $other (result (ref $opt))
(br $other
;; But this doesn't require anything, so $opt will be optimized.
(struct.new_default $opt)
)
)
)
(struct.new $super)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $if (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (if (result (ref $sub))
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $if
(drop
(if (result (ref $super))
(i32.const 0)
;; This requires $sub <: $super.
(then
(struct.new $sub)
)
(else
(struct.new $sub)
)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $loop (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (loop $loop-in (result (ref $sub))
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $loop
(drop
(loop (result (ref $super))
;; This requires $sub <: $super.
(struct.new $sub)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $loop (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $super (result (ref $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $sub (result (ref $sub))
;; CHECK-NEXT: (br_table $super $sub
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $loop
(drop
(block $super (result (ref $super))
(drop
(block $sub (result (ref $sub))
;; This requires $sub <: $super.
(br_table $super $sub
(struct.new $sub)
(i32.const 0)
)
)
)
(unreachable)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $br-table (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $super (result (ref $sub))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $sub (result (ref $sub))
;; CHECK-NEXT: (br_table $sub $super
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-table
(drop
(block $super (result (ref $super))
(drop
(block $sub (result (ref $sub))
;; Same as above with labels reversed. This requires $sub <: $super.
(br_table $sub $super
(struct.new $sub)
(i32.const 0)
)
)
)
(unreachable)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func (param (ref $super))))
;; CHECK: (func $call (type $2) (param $0 (ref $super))
;; CHECK-NEXT: (call $call
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call (param (ref $super))
;; This requires $sub <: $super
(call $call
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func (result (ref $sub))))
;; CHECK: (type $3 (func (result (ref $super))))
;; CHECK: (func $return-call (type $3) (result (ref $super))
;; CHECK-NEXT: (return_call $callee)
;; CHECK-NEXT: )
(func $return-call (result (ref $super))
;; This requires $sub <: $super
(return_call $callee)
)
;; CHECK: (func $callee (type $2) (result (ref $sub))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $callee (result (ref $sub))
(unreachable)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func (param (ref $super))))
;; CHECK: (table $t 1 1 funcref)
(table $t 1 1 funcref)
;; CHECK: (func $call-indirect (type $2) (param $0 (ref $super))
;; CHECK-NEXT: (call_indirect $t (type $2)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-indirect (param (ref $super))
;; This requires $sub <: $super.
(call_indirect $t (param (ref $super))
(struct.new $sub)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func (result (ref $sub))))
;; CHECK: (type $3 (func (result (ref $super))))
;; CHECK: (table $t 1 1 funcref)
(table $t 1 1 funcref)
;; CHECK: (func $return-call-indirect (type $3) (result (ref $super))
;; CHECK-NEXT: (return_call_indirect $t (type $2)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $return-call-indirect (result (ref $super))
;; This requires $sub <: $super.
(return_call_indirect $t (result (ref $sub))
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $sub (sub (func)))
;; CHECK: (type $super (sub (func)))
(type $super (sub (func)))
(type $sub (sub $super (func)))
;; CHECK: (table $t 1 1 (ref null $super))
(table $t 1 1 (ref null $super))
;; CHECK: (func $call-indirect-table (type $sub)
;; CHECK-NEXT: (call_indirect $t (type $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-indirect-table (type $sub)
;; This does *not* require $sub <: $super on its own, although if that
;; subtyping is not required at all, then it must be impossible for the table
;; to contain a $sub and this call will trap.
(call_indirect $t (type $sub)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $local-set (type $2)
;; CHECK-NEXT: (local $l (ref null $super))
;; CHECK-NEXT: (local.set $l
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $local-set
(local $l (ref null $super))
;; This requires $sub <: $super.
(local.set $l
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $local-tee (type $2)
;; CHECK-NEXT: (local $l (ref null $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $l
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $local-tee
(local $l (ref null $super))
(drop
;; This requires $sub <: $super.
(local.tee $l
(struct.new $sub)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (global $g (mut (ref null $super)) (ref.null none))
(global $g (mut (ref null $super)) (ref.null none))
;; CHECK: (func $global-set (type $2)
;; CHECK-NEXT: (global.set $g
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $global-set
;; This requires $sub <: $super.
(global.set $g
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub2 (sub $super (struct (field i32))))
;; CHECK: (type $sub1 (sub $super (struct )))
(type $sub1 (sub $super (struct)))
(type $sub2 (sub $super (struct i32)))
;; CHECK: (type $3 (func))
;; CHECK: (func $select (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select (result (ref $super))
;; CHECK-NEXT: (struct.new_default $sub1)
;; CHECK-NEXT: (struct.new_default $sub2)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $select
(drop
;; This requires $sub1 <: $super and $sub2 <: super.
(select (result (ref $super))
(struct.new $sub1)
(struct.new_default $sub2)
(i32.const 0)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func (result (ref $super))))
;; CHECK: (func $return (type $2) (result (ref $super))
;; CHECK-NEXT: (return
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $return (result (ref $super))
(return
;; This requires $sub <: $super.
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $sub (sub (struct )))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $return-none (type $2)
;; CHECK-NEXT: (local $super (ref null $super))
;; CHECK-NEXT: (local $sub (ref null $sub))
;; CHECK-NEXT: (return)
;; CHECK-NEXT: )
(func $return-none
(local $super (ref null $super))
(local $sub (ref null $sub))
;; Check that we don't get confused by bare returns.
(return)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super2 (sub (struct )))
;; CHECK: (type $sub2 (sub $super2 (struct )))
;; CHECK: (type $super1 (sub (struct )))
(type $super1 (sub (struct)))
(type $super2 (sub (struct)))
;; CHECK: (type $sub1 (sub $super1 (struct )))
(type $sub1 (sub $super1 (struct)))
(type $sub2 (sub $super2 (struct)))
)
;; CHECK: (type $4 (func (result (ref $super1) (ref $super2))))
;; CHECK: (func $return-many (type $4) (result (ref $super1) (ref $super2))
;; CHECK-NEXT: (return
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (struct.new_default $sub1)
;; CHECK-NEXT: (struct.new_default $sub2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $return-many (result (ref $super1) (ref $super2))
;; This requires $sub1 <: $super1 and $sub2 <: super2.
(return
(tuple.make 2
(struct.new $sub1)
(struct.new $sub2)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (table $t 1 1 (ref null $super))
(table $t 1 1 (ref null $super))
;; CHECK: (func $table-set (type $2)
;; CHECK-NEXT: (table.set $t
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $table-set
;; This requires $sub <: $super.
(table.set $t
(i32.const 0)
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (table $t 1 1 (ref null $super))
(table $t 1 1 (ref null $super))
;; CHECK: (func $table-fill (type $2)
;; CHECK-NEXT: (table.fill $t
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $table-fill
;; This requires $sub <: $super.
(table.fill $t
(i32.const 0)
(struct.new $sub)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $0 (func))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (table $super 1 1 (ref null $super))
(table $super 1 1 (ref null $super))
;; CHECK: (table $sub 1 1 (ref null $sub))
(table $sub 1 1 (ref null $sub))
;; CHECK: (func $table-copy (type $0)
;; CHECK-NEXT: (table.copy $super $sub
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $table-copy
;; This requires $sub <: $super.
(table.copy $super $sub
(i32.const 0)
(i32.const 0)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $try (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (try $try (result (ref $super))
;; CHECK-NEXT: (do
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (catch_all
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $try
(drop
(try (result (ref $super))
(do
;; This requires $sub <: $super.
(struct.new $sub)
)
(catch_all
(struct.new $super)
)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $try-catch (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (try $try (result (ref $super))
;; CHECK-NEXT: (do
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: (catch_all
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $try-catch
(drop
(try (result (ref $super))
(do
(struct.new $super)
)
(catch_all
;; This requires $sub <: $super.
(struct.new $sub)
)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (type $3 (func (param (ref $super))))
;; CHECK: (type $4 (func (param (ref $super))))
;; CHECK: (tag $t (param (ref $super)))
(tag $t (param (ref $super)))
;; CHECK: (func $throw (type $2)
;; CHECK-NEXT: (throw $t
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $throw
(throw $t
;; This requires $sub <: $super.
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $f (func (param (ref $super))))
(type $f (func (param (ref $super))))
;; CHECK: (elem declare func $call-ref)
;; CHECK: (func $call-ref (type $f) (param $0 (ref $super))
;; CHECK-NEXT: (call_ref $f
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (ref.func $call-ref)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable CallRef we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable CallRef we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null nofunc)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-ref (type $f) (param (ref $super))
;; This requires $sub <: $super.
(call_ref $f
(struct.new $sub)
(ref.func $call-ref)
)
;; This should not trip us up.
(call_ref $f
(struct.new $sub)
(unreachable)
)
;; Nor should this.
(call_ref $f
(struct.new $sub)
(ref.null nofunc)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $f (func (result (ref $sub))))
(type $f (func (result (ref $sub))))
;; CHECK: (type $3 (func (result (ref $super))))
;; CHECK: (elem declare func $callee)
;; CHECK: (func $return-call-ref (type $3) (result (ref $super))
;; CHECK-NEXT: (return_call_ref $f
;; CHECK-NEXT: (ref.func $callee)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $return-call-ref (result (ref $super))
;; This requires $sub <: $super.
(return_call_ref $f
(ref.func $callee)
)
)
;; CHECK: (func $callee (type $f) (result (ref $sub))
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $callee (result (ref $sub))
(unreachable)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $br-on-non-null (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref $super))
;; CHECK-NEXT: (br_on_non_null $l
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-non-null
(drop
(block $l (result (ref $super))
;; This requires $sub <: $super.
(br_on_non_null $l
(struct.new $sub)
)
(struct.new $super)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $br-on-cast (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref $super))
;; CHECK-NEXT: (br_on_cast $l (ref $super) (ref $sub)
;; CHECK-NEXT: (struct.new_default $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast
(drop
(block $l (result (ref $super))
;; This requires $sub <: $super.
(br_on_cast $l anyref (ref $sub)
(struct.new $super)
)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $2 (func))
;; CHECK: (func $br-on-cast-fail (type $2)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $l (result (ref $sub))
;; CHECK-NEXT: (br_on_cast_fail $l (ref $sub) (ref none)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast-fail
(drop
(block $l (result (ref $super))
;; This requires $sub <: $super.
(br_on_cast_fail $l anyref (ref none)
(struct.new $sub)
)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $struct (sub (struct (field (ref null $super)))))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $struct (sub (struct (ref null $super))))
;; CHECK: (type $3 (func))
;; CHECK: (func $struct-new (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new $struct
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $struct)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable StructNew we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $struct-new
(drop
;; This requires $sub <: $super.
(struct.new $struct
(struct.new $sub)
)
)
(drop
;; This should not trip us up.
(struct.new_default $struct)
)
;; Nor should this.
(struct.new $struct
(unreachable)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $struct (sub (struct (field (mut (ref null $super))))))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $struct (sub (struct (mut (ref null $super)))))
;; CHECK: (type $3 (func (param (ref null $struct))))
;; CHECK: (func $struct-set (type $3) (param $struct (ref null $struct))
;; CHECK-NEXT: (struct.set $struct 0
;; CHECK-NEXT: (local.get $struct)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable StructSet we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable StructSet we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $struct-set (param $struct (ref null $struct))
;; This requires $sub <: $super.
(struct.set $struct 0
(local.get $struct)
(struct.new $sub)
)
;; This should not trip us up.
(struct.set $struct 0
(unreachable)
(struct.new $sub)
)
;; Nor should this.
(struct.set $struct 0
(ref.null none)
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $array (sub (array (ref null $super))))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $array (sub (array (ref null $super))))
;; CHECK: (type $3 (func))
;; CHECK: (func $array-new (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (array.new $array
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (array.new_default $array
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block ;; (replaces unreachable ArrayNew we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-new
(drop
;; This requires $sub <: $super.
(array.new $array
(struct.new $sub)
(i32.const 0)
)
)
(drop
;; This should not trip us up.
(array.new_default $array
(i32.const 0)
)
)
(drop
;; Nor should this.
(array.new $array
(unreachable)
(i32.const 0)
)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $array (sub (array (ref null $super))))
;; CHECK: (type $1 (func))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $array (sub (array (ref null $super))))
;; CHECK: (elem $e (ref null $sub))
(elem $e (ref null $sub))
;; CHECK: (func $array-new-elem (type $1)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (array.new_elem $array $e
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable ArrayNewElem we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-new-elem
(drop
;; This requires $sub <: $super.
(array.new_elem $array $e
(i32.const 0)
(i32.const 0)
)
)
;; This should not trip us up.
(array.new_elem $array $e
(unreachable)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $array (sub (array (ref null $super))))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $array (sub (array (ref null $super))))
;; CHECK: (type $3 (func))
;; CHECK: (func $array-new-fixed (type $3)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (array.new_fixed $array 1
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable ArrayNewFixed we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-new-fixed
(drop
;; This requires $sub <: $super.
(array.new_fixed $array 1
(struct.new $sub)
)
)
;; This should not trip us up.
(array.new_fixed $array 1
(unreachable)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $array (sub (array (mut (ref null $super)))))
(type $array (sub (array (mut (ref null $super)))))
;; CHECK: (type $3 (func))
;; CHECK: (func $array-set (type $3)
;; CHECK-NEXT: (array.set $array
;; CHECK-NEXT: (array.new_fixed $array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable ArraySet we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block ;; (replaces unreachable ArraySet we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-set
;; This requires $sub <: $super.
(array.set $array
(array.new_fixed $array 0)
(i32.const 0)
(struct.new $sub)
)
;; This should not trip us up.
(array.set $array
(unreachable)
(i32.const 0)
(struct.new $sub)
)
;; Nor should this.
(array.set $array
(ref.null none)
(i32.const 0)
(struct.new $sub)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $sub-array (sub (array (mut (ref null $sub)))))
;; CHECK: (type $super-array (sub (array (mut (ref null $super)))))
(type $super-array (sub (array (mut (ref null $super)))))
(type $sub-array (sub (array (mut (ref null $sub)))))
;; CHECK: (type $4 (func))
;; CHECK: (func $array-copy (type $4)
;; CHECK-NEXT: (array.copy $super-array $sub-array
;; CHECK-NEXT: (array.new_fixed $super-array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (array.new_fixed $sub-array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (array.new_fixed $sub-array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (array.new_fixed $super-array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-copy
;; This requires $sub <: $super.
(array.copy $super-array $sub-array
(array.new_fixed $super-array 0)
(i32.const 0)
(array.new_fixed $sub-array 0)
(i32.const 0)
(i32.const 0)
)
;; This should not trip us up.
(array.copy $super-array $sub-array
(unreachable)
(i32.const 0)
(array.new_fixed $sub-array 0)
(i32.const 0)
(i32.const 0)
)
;; Nor should this.
(array.copy $super-array $sub-array
(array.new_fixed $super-array 0)
(i32.const 0)
(ref.null none)
(i32.const 0)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
;; CHECK: (type $array (sub (array (mut (ref null $super)))))
(type $array (sub (array (mut (ref null $super)))))
;; CHECK: (type $3 (func))
;; CHECK: (func $array-fill (type $3)
;; CHECK-NEXT: (array.fill $array
;; CHECK-NEXT: (array.new_fixed $array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (struct.new_default $sub)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-fill
;; This requires $sub <: $super.
(array.fill $array
(array.new_fixed $array 0)
(i32.const 0)
(struct.new $sub)
(i32.const 0)
)
;; This should not trip us up.
(array.fill $array
(unreachable)
(i32.const 0)
(struct.new $sub)
(i32.const 0)
)
;; Nor should this.
(array.fill $array
(ref.null none)
(i32.const 0)
(struct.new $sub)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $array (sub (array (mut (ref null $super)))))
;; CHECK: (type $1 (func))
;; CHECK: (type $super (sub (struct )))
(type $super (sub (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $super (struct)))
(type $array (sub (array (mut (ref null $super)))))
;; CHECK: (elem $e (ref null $sub))
(elem $e (ref null $sub))
;; CHECK: (func $array-init-elem (type $1)
;; CHECK-NEXT: (array.init_elem $array $e
;; CHECK-NEXT: (array.new_fixed $array 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-init-elem
;; This requires $sub <: $super.
(array.init_elem $array $e
(array.new_fixed $array 0)
(i32.const 0)
(i32.const 0)
(i32.const 0)
)
;; This should not trip us up.
(array.init_elem $array $e
(unreachable)
(i32.const 0)
(i32.const 0)
(i32.const 0)
)
;; Nor should this.
(array.init_elem $array $e
(ref.null none)
(i32.const 0)
(i32.const 0)
(i32.const 0)
)
)
)
(module
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct )))
(type $super (sub (struct)))
(type $mid (sub $super (struct)))
;; CHECK: (type $sub (sub $super (struct )))
(type $sub (sub $mid (struct)))
;; $sub <: $super, but it no longer needs to be related to $mid.
;; CHECK: (global $g (ref $super) (struct.new_default $sub))
(global $g (ref $super) (struct.new $sub))
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (ref null $mid)))))
(type $super (sub (struct (ref null $mid))))
;; CHECK: (type $mid (sub $super (struct (field (ref null $mid)) (field i32))))
(type $mid (sub $super (struct (ref null $mid) i32)))
;; CHECK: (type $sub (sub $mid (struct (field (ref null $sub)) (field i32) (field i32))))
(type $sub (sub $mid (struct (ref null $sub) i32 i32)))
)
;; Same as above, but now that transitively requires $sub <: $mid, so we don't
;; end up changing anything.
;; CHECK: (global $g (ref $super) (struct.new_default $sub))
(global $g (ref $super) (struct.new_default $sub))
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (struct (field (ref null $super)))))
(type $super (sub (struct (ref null $super))))
;; CHECK: (type $mid (sub $super (struct (field (ref null $super)) (field i32))))
(type $mid (sub $super (struct (ref null $super) i32)))
;; CHECK: (type $sub (sub $mid (struct (field (ref null $sub)) (field i32) (field i32))))
(type $sub (sub $mid (struct (ref null $sub) i32 i32)))
)
;; Similar, but now we directly require that $sub <: $mid and transitively
;; require that $sub <: $super, so again we cannot change anything.
;; CHECK: (global $g (ref $mid) (struct.new_default $sub))
(global $g (ref $mid) (struct.new_default $sub))
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $X (sub (struct )))
(type $X (sub (struct)))
;; CHECK: (type $Y (sub $X (struct )))
(type $Y (sub $X (struct)))
;; CHECK: (type $super (sub (struct (field (ref null $mid)))))
(type $super (sub (struct (ref null $mid))))
;; CHECK: (type $mid (sub $super (struct (field (ref null $sub)) (field (ref null $X)))))
(type $mid (sub $super (struct (ref null $sub) (ref null $X))))
;; CHECK: (type $sub (sub $mid (struct (field (ref null $sub)) (field (ref null $Y)))))
(type $sub (sub $mid (struct (ref null $sub) (ref null $Y))))
)
;; Require $sub <: $super, which transitively requires $sub <: $mid, which then
;; requires $Y <: $X. This only works because we put $sub back in the work list
;; when we find a more refined supertype for it.
;; CHECK: (global $g (ref $super) (struct.new_default $sub))
(global $g (ref $super) (struct.new_default $sub))
)