| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. |
| ;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s |
| |
| ;; $struct is our main test class. $desc is $struct's descriptor. |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| (type $struct (sub (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $desc (sub (describes $struct) (struct (field funcref)))) |
| (type $desc (sub (describes $struct) (struct (field funcref)))) |
| ) |
| |
| ;; CHECK: (type $2 (func (result i32))) |
| |
| ;; CHECK: (type $3 (func)) |
| |
| ;; CHECK: (global $desc (ref (exact $desc)) (struct.new $desc |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: )) |
| (global $desc (ref (exact $desc)) (struct.new $desc |
| (ref.func $func) |
| )) |
| |
| ;; CHECK: (global $struct (ref $struct) (struct.new_desc $struct |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 300) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: )) |
| (global $struct (ref $struct) (struct.new_desc $struct |
| (i32.const 100) |
| (i32.const 200) |
| (i32.const 300) |
| (global.get $desc) |
| )) |
| |
| ;; CHECK: (elem declare func $func) |
| |
| ;; CHECK: (export "desc" (func $desc)) |
| |
| ;; CHECK: (export "struct" (func $struct)) |
| |
| ;; CHECK: (func $func (type $2) (result i32) |
| ;; CHECK-NEXT: (i32.const -1) |
| ;; CHECK-NEXT: ) |
| (func $func (result i32) |
| (i32.const -1) |
| ) |
| |
| ;; CHECK: (func $desc (type $3) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $desc))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $2))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $desc))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $desc (export "desc") |
| ;; Show we can infer the descriptor. |
| (drop |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ;; Show we can read from the descriptor. |
| (drop |
| (struct.get $desc 0 |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $struct (type $3) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 300) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $struct (export "struct") |
| ;; Show we don't disrupt normal struct field inference. Field 1 is |
| ;; particuarly interesting as we represent descriptors as field -1 |
| ;; internally. |
| (drop |
| (struct.get $struct 0 |
| (global.get $struct) |
| ) |
| ) |
| (drop |
| (struct.get $struct 1 |
| (global.get $struct) |
| ) |
| ) |
| (drop |
| (struct.get $struct 2 |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; As above, but now we have a parent and subtype of $struct. The parent has no |
| ;; descriptor, while the subtype does. |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $parent (sub (struct (field i32) (field i32) (field i32)))) |
| (type $parent (sub (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $struct (sub $parent (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| (type $struct (sub $parent (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $desc (sub (describes $struct) (struct (field funcref)))) |
| (type $desc (sub (describes $struct) (struct (field funcref)))) |
| |
| ;; CHECK: (type $sub (sub $struct (descriptor $subdesc) (struct (field i32) (field i32) (field i32)))) |
| (type $sub (sub $struct (descriptor $subdesc) (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $subdesc (sub $desc (describes $sub) (struct (field funcref)))) |
| (type $subdesc (sub $desc (describes $sub) (struct (field funcref)))) |
| ) |
| |
| |
| ;; CHECK: (type $5 (func)) |
| |
| ;; CHECK: (type $6 (func (result i32))) |
| |
| ;; CHECK: (global $parent (ref $parent) (struct.new $parent |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 300) |
| ;; CHECK-NEXT: )) |
| (global $parent (ref $parent) (struct.new $parent |
| (i32.const 10) ;; disagrees with the child |
| (i32.const 200) ;; agrees with the child |
| (i32.const 300) ;; agrees with the child |
| )) |
| |
| ;; CHECK: (global $desc (ref (exact $desc)) (struct.new $desc |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: )) |
| (global $desc (ref (exact $desc)) (struct.new $desc |
| (ref.func $func) |
| )) |
| |
| ;; CHECK: (global $struct (ref $struct) (struct.new_desc $struct |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 300) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: )) |
| (global $struct (ref $struct) (struct.new_desc $struct |
| (i32.const 100) |
| (i32.const 200) |
| (i32.const 300) |
| (global.get $desc) |
| )) |
| |
| ;; CHECK: (global $subdesc (ref (exact $subdesc)) (struct.new $subdesc |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: )) |
| (global $subdesc (ref (exact $subdesc)) (struct.new $subdesc |
| (ref.func $func) ;; agrees with parent |
| )) |
| |
| ;; CHECK: (elem declare func $func) |
| |
| ;; CHECK: (export "desc" (func $desc)) |
| |
| ;; CHECK: (export "parent" (func $parent)) |
| |
| ;; CHECK: (export "sub" (func $sub)) |
| |
| ;; CHECK: (export "struct" (func $struct)) |
| |
| ;; CHECK: (func $func (type $6) (result i32) |
| ;; CHECK-NEXT: (i32.const -1) |
| ;; CHECK-NEXT: ) |
| (func $func (result i32) |
| (i32.const -1) |
| ) |
| |
| ;; CHECK: (func $desc (type $5) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $6))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $desc (export "desc") |
| ;; We cannot infer the descriptor: the subtype has a different one. |
| (drop |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ;; While we can't infer the descriptor, we *can* infer the value in the |
| ;; descriptor, as all descriptors have the same value. |
| (drop |
| (struct.get $desc 0 |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $parent (type $5) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.get $parent 0 |
| ;; CHECK-NEXT: (global.get $parent) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.get $parent 2 |
| ;; CHECK-NEXT: (global.get $parent) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $parent (export "parent") |
| ;; Show we don't disrupt the parent's inference. We can infer field 1, which |
| ;; is in agreement among all possible subtypes. |
| (drop |
| (struct.get $parent 0 |
| (global.get $parent) |
| ) |
| ) |
| (drop |
| (struct.get $parent 1 |
| (global.get $parent) |
| ) |
| ) |
| (drop |
| (struct.get $parent 2 |
| (global.get $parent) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $sub (type $5) |
| ;; CHECK-NEXT: (local $temp (ref $sub)) |
| ;; CHECK-NEXT: (local.set $temp |
| ;; CHECK-NEXT: (struct.new_desc $sub |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 333) |
| ;; CHECK-NEXT: (global.get $subdesc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $subdesc))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $sub |
| ;; CHECK-NEXT: (local.get $temp) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $subdesc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 333) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $sub (export "sub") |
| (local $temp (ref $sub)) |
| ;; Test $sub, and for variety, not using globals. |
| (local.set $temp |
| (struct.new_desc $sub |
| (i32.const 100) ;; agrees with parent |
| (i32.const 200) ;; agrees with parent |
| (i32.const 333) ;; disagrees with parent |
| (global.get $subdesc) |
| ) |
| ) |
| ;; We can infer the descriptor. |
| (drop |
| (ref.get_desc $sub |
| (local.get $temp) |
| ) |
| ) |
| ;; We can infer all these. |
| (drop |
| (struct.get $sub 0 |
| (local.get $temp) |
| ) |
| ) |
| (drop |
| (struct.get $sub 1 |
| (local.get $temp) |
| ) |
| ) |
| (drop |
| (struct.get $sub 2 |
| (local.get $temp) |
| ) |
| ) |
| ) |
| |
| ;; CHECK: (func $struct (type $5) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.get $struct 2 |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $struct (export "struct") |
| ;; We can infer the first two. |
| (drop |
| (struct.get $struct 0 |
| (global.get $struct) |
| ) |
| ) |
| (drop |
| (struct.get $struct 1 |
| (global.get $struct) |
| ) |
| ) |
| (drop |
| (struct.get $struct 2 |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; As above, but now the descriptor's funcref fields do not agree, so we cannot |
| ;; infer the value there. |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (sub (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| (type $struct (sub (descriptor $desc) (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $desc (sub (describes $struct) (struct (field funcref)))) |
| (type $desc (sub (describes $struct) (struct (field funcref)))) |
| |
| ;; CHECK: (type $sub (sub $struct (descriptor $subdesc) (struct (field i32) (field i32) (field i32)))) |
| (type $sub (sub $struct (descriptor $subdesc) (struct (field i32) (field i32) (field i32)))) |
| |
| ;; CHECK: (type $subdesc (sub $desc (describes $sub) (struct (field funcref)))) |
| (type $subdesc (sub $desc (describes $sub) (struct (field funcref)))) |
| ) |
| |
| ;; CHECK: (type $4 (func (result i32))) |
| |
| ;; CHECK: (type $5 (func)) |
| |
| ;; CHECK: (global $desc (ref (exact $desc)) (struct.new $desc |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: )) |
| (global $desc (ref (exact $desc)) (struct.new $desc |
| (ref.func $func) |
| )) |
| |
| ;; CHECK: (global $struct (ref $struct) (struct.new_desc $struct |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 300) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: )) |
| (global $struct (ref $struct) (struct.new_desc $struct |
| (i32.const 100) |
| (i32.const 200) |
| (i32.const 300) |
| (global.get $desc) |
| )) |
| |
| ;; CHECK: (global $subdesc (ref (exact $subdesc)) (struct.new $subdesc |
| ;; CHECK-NEXT: (ref.func $test) |
| ;; CHECK-NEXT: )) |
| (global $subdesc (ref (exact $subdesc)) (struct.new $subdesc |
| (ref.func $test) ;; disagrees with parent |
| )) |
| |
| ;; CHECK: (elem declare func $func) |
| |
| ;; CHECK: (export "test" (func $test)) |
| |
| ;; CHECK: (func $func (type $4) (result i32) |
| ;; CHECK-NEXT: (i32.const -1) |
| ;; CHECK-NEXT: ) |
| (func $func (result i32) |
| (i32.const -1) |
| ) |
| |
| ;; CHECK: (func $test (type $5) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.new_desc $sub |
| ;; CHECK-NEXT: (i32.const 100) |
| ;; CHECK-NEXT: (i32.const 200) |
| ;; CHECK-NEXT: (i32.const 333) |
| ;; CHECK-NEXT: (global.get $subdesc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $desc))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (ref.cast (ref (exact $struct)) |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (struct.get $desc 0 |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $4))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $desc))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $struct |
| ;; CHECK-NEXT: (ref.cast (ref (exact $struct)) |
| ;; CHECK-NEXT: (global.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $desc) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.func $func) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $test (export "test") |
| (drop |
| (struct.new_desc $sub |
| (i32.const 100) ;; agrees with parent |
| (i32.const 200) ;; agrees with parent |
| (i32.const 333) ;; disagrees with parent |
| (global.get $subdesc) |
| ) |
| ) |
| ;; We cannot infer the descriptor due to the subtype. |
| (drop |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ;; Using an exact $struct, we can. |
| (drop |
| (ref.get_desc $struct |
| (ref.cast (ref (exact $struct)) |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ;; We cannot infer from the descriptor due to the different descriptor |
| ;; subtypes. |
| (drop |
| (struct.get $desc 0 |
| (ref.get_desc $struct |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ;; Using an exact $struct, we can. |
| (drop |
| (struct.get $desc 0 |
| (ref.get_desc $struct |
| (ref.cast (ref (exact $struct)) |
| (global.get $struct) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; Descriptor chain. |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $A (descriptor $B) (struct (field i32))) |
| (type $A (descriptor $B) (struct (field i32))) |
| |
| ;; CHECK: (type $B (describes $A) (descriptor $C) (struct (field i32))) |
| (type $B (describes $A) (descriptor $C) (struct (field i32))) |
| |
| ;; CHECK: (type $C (describes $B) (struct (field i32))) |
| (type $C (describes $B) (struct (field i32))) |
| ) |
| |
| ;; CHECK: (type $3 (func)) |
| |
| ;; CHECK: (global $C (ref (exact $C)) (struct.new $C |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: )) |
| (global $C (ref (exact $C)) (struct.new $C |
| (i32.const 10) |
| )) |
| |
| ;; CHECK: (global $B (ref (exact $B)) (struct.new_desc $B |
| ;; CHECK-NEXT: (i32.const 20) |
| ;; CHECK-NEXT: (global.get $C) |
| ;; CHECK-NEXT: )) |
| (global $B (ref (exact $B)) (struct.new_desc $B |
| (i32.const 20) |
| (global.get $C) |
| )) |
| |
| ;; CHECK: (global $A (ref (exact $A)) (struct.new_desc $A |
| ;; CHECK-NEXT: (i32.const 30) |
| ;; CHECK-NEXT: (global.get $B) |
| ;; CHECK-NEXT: )) |
| (global $A (ref (exact $A)) (struct.new_desc $A |
| (i32.const 30) |
| (global.get $B) |
| )) |
| |
| ;; CHECK: (export "test" (func $test)) |
| |
| ;; CHECK: (func $test (type $3) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $B))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $A |
| ;; CHECK-NEXT: (global.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $B) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $C))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $B |
| ;; CHECK-NEXT: (global.get $B) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $C) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result i32) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (block (result (ref (exact $C))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $B |
| ;; CHECK-NEXT: (block (result (ref (exact $B))) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (ref.get_desc $A |
| ;; CHECK-NEXT: (global.get $A) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $B) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (global.get $C) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (i32.const 10) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $test (export "test") |
| ;; We can infer these. |
| (drop |
| (ref.get_desc $A |
| (global.get $A) |
| ) |
| ) |
| (drop |
| (ref.get_desc $B |
| (global.get $B) |
| ) |
| ) |
| ;; We can do so all at once too. |
| (drop |
| (struct.get $C 0 |
| (ref.get_desc $B |
| (ref.get_desc $A |
| (global.get $A) |
| ) |
| ) |
| ) |
| ) |
| ) |
| ) |