;; 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)) )