summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/type-generalizing.wast1335
1 files changed, 1316 insertions, 19 deletions
diff --git a/test/lit/passes/type-generalizing.wast b/test/lit/passes/type-generalizing.wast
index fed327727..c874cc76c 100644
--- a/test/lit/passes/type-generalizing.wast
+++ b/test/lit/passes/type-generalizing.wast
@@ -3,20 +3,54 @@
;; RUN: foreach %s %t wasm-opt --experimental-type-generalizing -all -S -o - | filecheck %s
(module
+ ;; CHECK: (type $void (func))
+ (type $void (func))
- ;; CHECK: (type $0 (func (result eqref)))
+ ;; CHECK: (type $1 (func (result eqref)))
- ;; CHECK: (type $1 (func))
+ ;; CHECK: (type $2 (func (param eqref)))
- ;; CHECK: (type $2 (func (param anyref)))
+ ;; CHECK: (type $3 (func (param eqref anyref)))
- ;; CHECK: (type $3 (func (param i31ref)))
+ ;; CHECK: (type $4 (func (param anyref)))
- ;; CHECK: (type $4 (func (param anyref eqref)))
+ ;; CHECK: (type $5 (func (param i31ref)))
- ;; CHECK: (type $5 (func (param eqref)))
+ ;; CHECK: (type $6 (func (param anyref eqref)))
- ;; CHECK: (func $unconstrained (type $1)
+ ;; CHECK: (type $7 (func (result i32)))
+
+ ;; CHECK: (type $8 (func (result nullref)))
+
+ ;; CHECK: (type $9 (func (result structref)))
+
+ ;; CHECK: (type $10 (func (result (ref eq))))
+
+ ;; CHECK: (type $11 (func (param (ref noextern)) (result anyref)))
+
+ ;; CHECK: (type $12 (func (param (ref noextern)) (result (ref any))))
+
+ ;; CHECK: (type $13 (func (result externref)))
+
+ ;; CHECK: (type $14 (func (result (ref extern))))
+
+ ;; CHECK: (type $15 (func (param anyref anyref)))
+
+ ;; CHECK: (global $global-eq (mut eqref) (ref.null none))
+ (global $global-eq (mut eqref) (ref.null none))
+
+ ;; CHECK: (global $global-i32 (mut i32) (i32.const 0))
+ (global $global-i32 (mut i32) (i32.const 0))
+
+ ;; CHECK: (table $func-table 0 0 funcref)
+ (table $func-table 0 0 funcref)
+
+ ;; CHECK: (table $eq-table 0 0 eqref)
+ (table $eq-table 0 0 eqref)
+
+ ;; CHECK: (elem declare func $ref-func)
+
+ ;; CHECK: (func $unconstrained (type $void)
;; CHECK-NEXT: (local $x i32)
;; CHECK-NEXT: (local $y anyref)
;; CHECK-NEXT: (local $z (anyref i32))
@@ -31,7 +65,7 @@
(local $z (anyref i32))
)
- ;; CHECK: (func $implicit-return (type $0) (result eqref)
+ ;; CHECK: (func $implicit-return (type $1) (result eqref)
;; CHECK-NEXT: (local $var eqref)
;; CHECK-NEXT: (local.get $var)
;; CHECK-NEXT: )
@@ -42,7 +76,7 @@
(local.get $var)
)
- ;; CHECK: (func $implicit-return-unreachable (type $0) (result eqref)
+ ;; CHECK: (func $implicit-return-unreachable (type $1) (result eqref)
;; CHECK-NEXT: (local $var anyref)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
@@ -54,7 +88,7 @@
(local.get $var)
)
- ;; CHECK: (func $if (type $0) (result eqref)
+ ;; CHECK: (func $if (type $1) (result eqref)
;; CHECK-NEXT: (local $x eqref)
;; CHECK-NEXT: (local $y eqref)
;; CHECK-NEXT: (if (result eqref)
@@ -63,7 +97,7 @@
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
- (func $if (result (eqref))
+ (func $if (result eqref)
(local $x i31ref)
(local $y i31ref)
(if (result i31ref)
@@ -75,7 +109,147 @@
)
)
- ;; CHECK: (func $local-set (type $1)
+ ;; CHECK: (func $loop (type $1) (result eqref)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (loop $loop-in (result eqref)
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $loop (result eqref)
+ (local $var i31ref)
+ ;; Require that typeof($var) <: eqref.
+ (loop (result i31ref)
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $br-sent (type $1) (result eqref)
+ ;; CHECK-NEXT: (local $var1 anyref)
+ ;; CHECK-NEXT: (local $var2 eqref)
+ ;; CHECK-NEXT: (block $l (result eqref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $var1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (br $l
+ ;; CHECK-NEXT: (local.get $var2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br-sent (result eqref)
+ (local $var1 i31ref)
+ (local $var2 i31ref)
+ (block $l (result i31ref)
+ ;; The call will be DCEd out, but this test and the implementation for `br`
+ ;; should be forward-compatible with a future where we do not have to run DCE
+ ;; before this pass.
+ (call $helper-any_any
+ ;; No requirements on $var1
+ (local.get $var1)
+ ;; Require that typeof($var2) <: eqref.
+ (br $l
+ (local.get $var2)
+ )
+ )
+ )
+ )
+
+ ;; CHECK: (func $br-no-sent (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (block $l
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (br $l)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br-no-sent
+ (local $var i31ref)
+ (block $l
+ ;; This call is DCEd out just like in the previous test.
+ (call $helper-any_any
+ ;; No requirements on $var
+ (local.get $var)
+ (br $l)
+ )
+ )
+ )
+
+ ;; CHECK: (func $br_table-sent (type $3) (param $eq eqref) (param $any anyref)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (local.set $eq
+ ;; CHECK-NEXT: (block $l1 (result eqref)
+ ;; CHECK-NEXT: (local.set $any
+ ;; CHECK-NEXT: (block $l2 (result eqref)
+ ;; CHECK-NEXT: (br_table $l1 $l2
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br_table-sent (param $eq eqref) (param $any anyref)
+ (local $var i31ref)
+ ;; Require typeof($var) <: eqref.
+ (local.set $eq
+ (block $l1 (result i31ref)
+ ;; Require typeof($var) <: anyref.
+ (local.set $any
+ (block $l2 (result i31ref)
+ (br_table $l1 $l2
+ (local.get $var)
+ (i32.const 0)
+ )
+ )
+ )
+ (unreachable)
+ )
+ )
+ )
+
+ ;; CHECK: (func $br_table-sent-reversed (type $3) (param $eq eqref) (param $any anyref)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (local.set $any
+ ;; CHECK-NEXT: (block $l1 (result eqref)
+ ;; CHECK-NEXT: (local.set $eq
+ ;; CHECK-NEXT: (block $l2 (result eqref)
+ ;; CHECK-NEXT: (br_table $l1 $l2
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $br_table-sent-reversed (param $eq eqref) (param $any anyref)
+ ;; Same as above, but with the sources of requirements flipped.
+ (local $var i31ref)
+ ;; Require typeof($var) <: anyref.
+ (local.set $any
+ (block $l1 (result i31ref)
+ ;; Require typeof($var) <: eqref.
+ (local.set $eq
+ (block $l2 (result i31ref)
+ (br_table $l1 $l2
+ (local.get $var)
+ (i32.const 0)
+ )
+ )
+ )
+ (unreachable)
+ )
+ )
+ )
+
+ ;; CHECK: (func $local-set (type $void)
;; CHECK-NEXT: (local $var anyref)
;; CHECK-NEXT: (local.set $var
;; CHECK-NEXT: (ref.i31
@@ -94,7 +268,7 @@
)
)
- ;; CHECK: (func $local-get-set (type $2) (param $dest anyref)
+ ;; CHECK: (func $local-get-set (type $4) (param $dest anyref)
;; CHECK-NEXT: (local $var anyref)
;; CHECK-NEXT: (local.set $dest
;; CHECK-NEXT: (local.get $var)
@@ -109,7 +283,7 @@
)
)
- ;; CHECK: (func $local-get-set-unreachable (type $3) (param $dest i31ref)
+ ;; CHECK: (func $local-get-set-unreachable (type $5) (param $dest i31ref)
;; CHECK-NEXT: (local $var anyref)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
@@ -126,7 +300,7 @@
)
)
- ;; CHECK: (func $local-get-set-join (type $4) (param $dest1 anyref) (param $dest2 eqref)
+ ;; CHECK: (func $local-get-set-join (type $6) (param $dest1 anyref) (param $dest2 eqref)
;; CHECK-NEXT: (local $var eqref)
;; CHECK-NEXT: (local.set $dest1
;; CHECK-NEXT: (local.get $var)
@@ -148,7 +322,7 @@
)
)
- ;; CHECK: (func $local-get-set-chain (type $0) (result eqref)
+ ;; CHECK: (func $local-get-set-chain (type $1) (result eqref)
;; CHECK-NEXT: (local $a eqref)
;; CHECK-NEXT: (local $b eqref)
;; CHECK-NEXT: (local $c eqref)
@@ -176,7 +350,7 @@
(local.get $c)
)
- ;; CHECK: (func $local-get-set-chain-out-of-order (type $0) (result eqref)
+ ;; CHECK: (func $local-get-set-chain-out-of-order (type $1) (result eqref)
;; CHECK-NEXT: (local $a eqref)
;; CHECK-NEXT: (local $b eqref)
;; CHECK-NEXT: (local $c eqref)
@@ -205,7 +379,7 @@
(local.get $c)
)
- ;; CHECK: (func $local-tee (type $5) (param $dest eqref)
+ ;; CHECK: (func $local-tee (type $2) (param $dest eqref)
;; CHECK-NEXT: (local $var eqref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.tee $dest
@@ -231,7 +405,7 @@
)
)
- ;; CHECK: (func $i31-get (type $1)
+ ;; CHECK: (func $i31-get (type $void)
;; CHECK-NEXT: (local $nullable i31ref)
;; CHECK-NEXT: (local $nonnullable i31ref)
;; CHECK-NEXT: (local.set $nonnullable
@@ -274,4 +448,1127 @@
)
)
)
+
+ ;; CHECK: (func $call (type $2) (param $x eqref)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (call $call
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call (param $x eqref)
+ ;; This will be optimized to eqref.
+ (local $var i31ref)
+ ;; Requires typeof($var) <: eqref.
+ (call $call
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $call_indirect (type $void)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (call_indirect $func-table (type $2)
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call_indirect
+ ;; This will be optimized to eqref.
+ (local $var i31ref)
+ ;; Requires typeof($var) <: eqref.
+ (call_indirect (param eqref)
+ (local.get $var)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $global-get (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (local $i32 i32)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (global.get $global-eq)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $i32
+ ;; CHECK-NEXT: (global.get $global-i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $global-get
+ (local $var eqref)
+ (local $i32 i32)
+ ;; The global type will remain unchanged and the local will be generalized.
+ (local.set $var
+ (global.get $global-eq)
+ )
+ ;; Non-reference typed globals are ok, too.
+ (local.set $i32
+ (global.get $global-i32)
+ )
+ )
+
+ ;; CHECK: (func $global-set (type $void)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (local $i32 i32)
+ ;; CHECK-NEXT: (global.set $global-eq
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.set $global-i32
+ ;; CHECK-NEXT: (local.get $i32)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $global-set
+ (local $var i31ref)
+ (local $i32 i32)
+ ;; Requires typeof($var) <: eqref.
+ (global.set $global-eq
+ (local.get $var)
+ )
+ ;; Non-reference typed globals are ok, too.
+ (global.set $global-i32
+ (local.get $i32)
+ )
+ )
+
+ ;; CHECK: (func $select (type $1) (result eqref)
+ ;; CHECK-NEXT: (local $var1 eqref)
+ ;; CHECK-NEXT: (local $var2 eqref)
+ ;; CHECK-NEXT: (select (result eqref)
+ ;; CHECK-NEXT: (local.get $var1)
+ ;; CHECK-NEXT: (local.get $var2)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $select (result eqref)
+ ;; Both of these will be generalized to eqref.
+ (local $var1 i31ref)
+ (local $var2 i31ref)
+ ;; Requires typeof($var1) <: eqref and typeof($var2) <: eqref.
+ (select (result i31ref)
+ (local.get $var1)
+ (local.get $var2)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $ref-null (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-null
+ (local $var i31ref)
+ ;; No constraints on $var.
+ (local.set $var
+ (ref.null none)
+ )
+ )
+
+ ;; CHECK: (func $ref-is-null (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.is_null
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-is-null
+ (local $var i31ref)
+ (drop
+ ;; No constraints on $var.
+ (ref.is_null
+ (local.get $var)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-func (type $void)
+ ;; CHECK-NEXT: (local $var funcref)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (ref.func $ref-func)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-func
+ (local $var (ref null $void))
+ ;; No constraints on $var.
+ (local.set $var
+ (ref.func $ref-func)
+ )
+ )
+
+ ;; CHECK: (func $ref-eq (type $void)
+ ;; CHECK-NEXT: (local $var1 eqref)
+ ;; CHECK-NEXT: (local $var2 eqref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.eq
+ ;; CHECK-NEXT: (local.get $var1)
+ ;; CHECK-NEXT: (local.get $var2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-eq
+ (local $var1 i31ref)
+ (local $var2 i31ref)
+ (drop
+ ;; Require that typeof($var1) <: eqref and that typeof($var2) <: eqref.
+ (ref.eq
+ (local.get $var1)
+ (local.get $var2)
+ )
+ )
+ )
+
+ ;; CHECK: (func $table-get (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (table.get $eq-table
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $table-get
+ (local $var eqref)
+ ;; No constraints on $var.
+ (local.set $var
+ (table.get $eq-table
+ (i32.const 0)
+ )
+ )
+ )
+
+ ;; CHECK: (func $table-set (type $void)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (table.set $eq-table
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $table-set
+ (local $var i31ref)
+ ;; Require typeof($var) <: eqref.
+ (table.set $eq-table
+ (i32.const 0)
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $table-fill (type $void)
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (table.fill $eq-table
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $table-fill
+ (local $var i31ref)
+ ;; Require typeof($var) <: eqref.
+ (table.fill $eq-table
+ (i32.const 0)
+ (local.get $var)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $ref-test (type $7) (result i32)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (ref.test nullref
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-test (result i32)
+ (local $var i31ref)
+ ;; No constraint on $var.
+ (ref.test structref
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $ref-cast (type $void)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (ref.cast i31ref
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-cast
+ (local $var i31ref)
+ ;; No constraint on $var.
+ (drop
+ (ref.cast i31ref
+ (local.get $var)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-limited (type $1) (result eqref)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (ref.cast i31ref
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-cast-limited (result eqref)
+ (local $var i31ref)
+ ;; No constraint on $var.
+ ;; TODO: We could eliminate the cast if we did constrain $var.
+ (ref.cast i31ref
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-more-limited (type $8) (result nullref)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (ref.cast nullref
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-cast-more-limited (result nullref)
+ (local $var i31ref)
+ ;; No constraint on $var.
+ (ref.cast nullref
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $ref-cast-lub (type $9) (result structref)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (ref.cast nullref
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-cast-lub (result structref)
+ (local $var i31ref)
+ ;; No constraint on $var.
+ (ref.cast structref
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $ref-as-non-null (type $10) (result (ref eq))
+ ;; CHECK-NEXT: (local $var eqref)
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $ref-as-non-null (result (ref eq))
+ (local $var i31ref)
+ ;; Require that typeof($var) <: eqref.
+ (ref.as_non_null
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $any-convert-extern-nullable (type $11) (param $x (ref noextern)) (result anyref)
+ ;; CHECK-NEXT: (local $var externref)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (extern.internalize
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $any-convert-extern-nullable (param $x (ref noextern)) (result anyref)
+ (local $var (ref noextern))
+ (local.set $var
+ (local.get $x)
+ )
+ ;; Require that typeof($var) <: externref.
+ (extern.internalize
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $any-convert-extern-non-nullable (type $12) (param $x (ref noextern)) (result (ref any))
+ ;; CHECK-NEXT: (local $var (ref extern))
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (local.get $x)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (extern.internalize
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $any-convert-extern-non-nullable (param $x (ref noextern)) (result (ref any))
+ (local $var (ref noextern))
+ (local.set $var
+ (local.get $x)
+ )
+ ;; Require that typeof($var) <: (ref extern).
+ (extern.internalize
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $extern-convert-any-nullable (type $13) (result externref)
+ ;; CHECK-NEXT: (local $var anyref)
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (ref.i31
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (extern.externalize
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $extern-convert-any-nullable (result externref)
+ (local $var (ref i31))
+ (local.set $var
+ (i31.new
+ (i32.const 0)
+ )
+ )
+ ;; Require that typeof($var) <: anyref.
+ (extern.externalize
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $extern-convert-any-non-nullable (type $14) (result (ref extern))
+ ;; CHECK-NEXT: (local $var (ref any))
+ ;; CHECK-NEXT: (local.set $var
+ ;; CHECK-NEXT: (ref.i31
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (extern.externalize
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $extern-convert-any-non-nullable (result (ref extern))
+ (local $var (ref i31))
+ (local.set $var
+ (i31.new
+ (i32.const 0)
+ )
+ )
+ ;; Require that typeof($var) <: anyref.
+ (extern.externalize
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $helper-any_any (type $15) (param $0 anyref) (param $1 anyref)
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $helper-any_any (param anyref anyref)
+ (unreachable)
+ )
+)
+
+(module
+ ;; CHECK: (type $top (sub (func (param i31ref) (result anyref))))
+ (type $top (sub (func (param i31ref) (result anyref))))
+ ;; CHECK: (type $mid (sub $top (func (param eqref) (result anyref))))
+ (type $mid (sub $top (func (param eqref) (result anyref))))
+ ;; CHECK: (type $2 (func (result eqref)))
+
+ ;; CHECK: (type $bot (sub $mid (func (param eqref) (result eqref))))
+ (type $bot (sub $mid (func (param eqref) (result eqref))))
+
+ ;; CHECK: (type $4 (func (result anyref)))
+
+ ;; CHECK: (func $call-ref-params-limited (type $4) (result anyref)
+ ;; CHECK-NEXT: (local $f (ref null $mid))
+ ;; CHECK-NEXT: (local $arg eqref)
+ ;; CHECK-NEXT: (call_ref $mid
+ ;; CHECK-NEXT: (local.get $arg)
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-ref-params-limited (result anyref)
+ (local $f (ref null $bot))
+ (local $arg i31ref)
+ ;; Require that typeof($f) <: $mid and that typeof($arg) <: eqref. In
+ ;; principle we could generalize $f up to $top, but then we wouldn't be able
+ ;; to generalize $arg at all.
+ (call_ref $bot
+ (local.get $arg)
+ (local.get $f)
+ )
+ )
+
+ ;; CHECK: (func $call-ref-results-limited (type $2) (result eqref)
+ ;; CHECK-NEXT: (local $f (ref null $bot))
+ ;; CHECK-NEXT: (local $arg eqref)
+ ;; CHECK-NEXT: (call_ref $bot
+ ;; CHECK-NEXT: (local.get $arg)
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-ref-results-limited (result eqref)
+ (local $f (ref null $bot))
+ (local $arg i31ref)
+ ;; Require that typeof($f) <: $bot because anything better would require a
+ ;; cast on the output. Also require that typeof($arg) <: eqref.
+ (call_ref $bot
+ (local.get $arg)
+ (local.get $f)
+ )
+ )
+
+ ;; CHECK: (func $call-ref-impossible (type $2) (result eqref)
+ ;; CHECK-NEXT: (local $f nullfuncref)
+ ;; CHECK-NEXT: (local $arg anyref)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $arg)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-ref-impossible (result eqref)
+ (local $f nullfuncref)
+ (local $arg i31ref)
+ ;; Require that typeof($f) <: nullref, but do not constrain $arg because the
+ ;; call_ref will not be reached.
+ (call_ref $bot
+ (local.get $arg)
+ (local.get $f)
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $top (sub (func (result anyref))))
+ (type $top (sub (func (result anyref))))
+ (type $mid (sub $top (func (result eqref))))
+ (type $bot (sub $mid (func (result i31ref))))
+
+ ;; CHECK: (type $1 (func (result anyref)))
+
+ ;; CHECK: (func $call-ref-no-limit (type $1) (result anyref)
+ ;; CHECK-NEXT: (local $f (ref null $top))
+ ;; CHECK-NEXT: (call_ref $top
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $call-ref-no-limit (result anyref)
+ (local $f (ref null $bot))
+ ;; Require that typeof($f) <: $top because that does not limit us in any way
+ ;; and we cannot possibly do better.
+ (call_ref $bot
+ (local.get $f)
+ )
+ )
+)
+
+(module
+
+ ;; CHECK: (type $0 (func (result anyref)))
+
+ ;; CHECK: (type $top (sub (struct (field (mut eqref)) (field eqref))))
+ (type $top (sub (struct (field (mut eqref)) (field eqref))))
+ ;; CHECK: (type $mid (sub $top (struct (field (mut eqref)) (field eqref) (field (mut eqref)))))
+ (type $mid (sub $top (struct (field (mut eqref)) (field eqref) (field (mut eqref)))))
+ ;; CHECK: (type $3 (func))
+
+ ;; CHECK: (type $bot (sub $mid (struct (field (mut eqref)) (field i31ref) (field (mut eqref)))))
+ (type $bot (sub $mid (struct (field (mut eqref)) (field i31ref) (field (mut eqref)))))
+
+ ;; CHECK: (type $struct (struct (field eqref) (field anyref)))
+ (type $struct (struct (field eqref) (field anyref)))
+
+ ;; CHECK: (type $6 (func (result i31ref)))
+
+ ;; CHECK: (func $struct-new (type $0) (result anyref)
+ ;; CHECK-NEXT: (local $var1 eqref)
+ ;; CHECK-NEXT: (local $var2 anyref)
+ ;; CHECK-NEXT: (struct.new $struct
+ ;; CHECK-NEXT: (local.get $var1)
+ ;; CHECK-NEXT: (local.get $var2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-new (result anyref)
+ (local $var1 i31ref)
+ (local $var2 i31ref)
+ ;; Require that typeof($var1) <: eqref and that typeof($var2) <: anyref.
+ (struct.new $struct
+ (local.get $var1)
+ (local.get $var2)
+ )
+ )
+
+ ;; CHECK: (func $struct-get (type $0) (result anyref)
+ ;; CHECK-NEXT: (local $var (ref null $top))
+ ;; CHECK-NEXT: (struct.get $top 1
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-get (result anyref)
+ (local $var (ref null $bot))
+ ;; Require that typeof($var) <: (ref null $top) because it has a field of the
+ ;; right type at index 1.
+ (struct.get $bot 1
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $struct-get-type (type $6) (result i31ref)
+ ;; CHECK-NEXT: (local $var (ref null $bot))
+ ;; CHECK-NEXT: (struct.get $bot 1
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-get-type (result i31ref)
+ (local $var (ref null $bot))
+ ;; Require that typeof($var) <: (ref null $bot) because further supertypes do
+ ;; not satisfy the requirement on the result type.
+ (struct.get $bot 1
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $struct-get-index (type $0) (result anyref)
+ ;; CHECK-NEXT: (local $var (ref null $mid))
+ ;; CHECK-NEXT: (struct.get $mid 2
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-get-index (result anyref)
+ (local $var (ref null $bot))
+ ;; Require that typeof($var) <: (ref null $mid) because further supertypes do
+ ;; not have a field at index 2.
+ (struct.get $bot 2
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $struct-get-impossible (type $0) (result anyref)
+ ;; CHECK-NEXT: (local $var nullref)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $var)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-get-impossible (result anyref)
+ (local $var nullref)
+ (struct.get $bot 0
+ (local.get $var)
+ )
+ )
+
+ ;; CHECK: (func $struct-set (type $3)
+ ;; CHECK-NEXT: (local $ref (ref null $top))
+ ;; CHECK-NEXT: (local $val eqref)
+ ;; CHECK-NEXT: (struct.set $top 0
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-set
+ (local $ref (ref null $bot))
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: (ref null $top) because it has a field at
+ ;; index 0 and require that typeof($val) <: eqref because that is the type of
+ ;; the field.
+ (struct.set $bot 0
+ (local.get $ref)
+ (local.get $val)
+ )
+ )
+
+ ;; CHECK: (func $struct-set-index (type $3)
+ ;; CHECK-NEXT: (local $ref (ref null $mid))
+ ;; CHECK-NEXT: (local $val eqref)
+ ;; CHECK-NEXT: (struct.set $mid 2
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-set-index
+ (local $ref (ref null $bot))
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: (ref null $mid) because further supertypes do
+ ;; not have a field at index 2 and require that typeof($val) <: eqref because
+ ;; that is the type of the field.
+ (struct.set $bot 2
+ (local.get $ref)
+ (local.get $val)
+ )
+ )
+
+ ;; CHECK: (func $struct-set-impossible (type $3)
+ ;; CHECK-NEXT: (local $ref nullref)
+ ;; CHECK-NEXT: (local $val anyref)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-set-impossible
+ (local $ref nullref)
+ (local $val nullref)
+ ;; Require that typeof($ref) <: nullref, but do not constrain $val.
+ (struct.set $bot 0
+ (local.get $ref)
+ (local.get $val)
+ )
+ )
+)
+
+(module
+ ;; CHECK: (type $0 (func))
+
+ ;; CHECK: (type $super-mut (sub (array (mut eqref))))
+
+ ;; CHECK: (type $super (sub (array eqref)))
+ (type $super (sub (array (field eqref))))
+ ;; CHECK: (type $3 (func (result anyref)))
+
+ ;; CHECK: (type $mut-bytes (sub (array (mut i8))))
+
+ ;; CHECK: (type $bytes (sub (array i8)))
+
+ ;; CHECK: (type $sub (sub $super (array i31ref)))
+ (type $sub (sub $super (array (field i31ref))))
+
+ (type $super-mut (sub (array (field (mut eqref)))))
+ (type $sub-mut (sub $super-mut (array (field (mut eqref)))))
+
+ (type $bytes (sub (array i8)))
+ (type $sub-bytes (sub $bytes (array i8)))
+
+ (type $mut-bytes (sub (array (mut i8))))
+ (type $sub-mut-bytes (sub $mut-bytes (array (mut i8))))
+
+ ;; CHECK: (data $data "")
+
+ ;; CHECK: (elem $elem i31ref)
+ (elem $elem i31ref)
+
+ (data $data "")
+
+ ;; CHECK: (func $array-new (type $3) (result anyref)
+ ;; CHECK-NEXT: (local $val eqref)
+ ;; CHECK-NEXT: (array.new $super
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new (result anyref)
+ (local $val i31ref)
+ ;; Require that typeof($val) <: eqref.
+ (array.new $super
+ (local.get $val)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-new-data (type $0)
+ ;; CHECK-NEXT: (local $val anyref)
+ ;; CHECK-NEXT: (local.set $val
+ ;; CHECK-NEXT: (array.new_data $bytes $data
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new-data
+ (local $val arrayref)
+ ;; No constraint on $val.
+ (local.set $val
+ (array.new_data $bytes $data
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array-new-elem (type $0)
+ ;; CHECK-NEXT: (local $val anyref)
+ ;; CHECK-NEXT: (local.set $val
+ ;; CHECK-NEXT: (array.new_elem $sub $elem
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new-elem
+ (local $val arrayref)
+ ;; No constraint on $val.
+ (local.set $val
+ (array.new_elem $sub $elem
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array-new-fixed (type $3) (result anyref)
+ ;; CHECK-NEXT: (local $val1 eqref)
+ ;; CHECK-NEXT: (local $val2 eqref)
+ ;; CHECK-NEXT: (array.new_fixed $super 2
+ ;; CHECK-NEXT: (local.get $val1)
+ ;; CHECK-NEXT: (local.get $val2)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-new-fixed (result anyref)
+ (local $val1 i31ref)
+ (local $val2 i31ref)
+ ;; Require that typeof($val1) <: eqref and that typeof($val2) <: eqref.
+ (array.new_fixed $super 2
+ (local.get $val1)
+ (local.get $val2)
+ )
+ )
+
+ ;; CHECK: (func $array-get (type $3) (result anyref)
+ ;; CHECK-NEXT: (local $val (ref null $super))
+ ;; CHECK-NEXT: (array.get $super
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-get (result anyref)
+ (local $val (ref null $sub))
+ ;; Require that typeof($val) <: (ref null $super).
+ (array.get $sub
+ (local.get $val)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-get-impossible (type $3) (result anyref)
+ ;; CHECK-NEXT: (local $val nullref)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-get-impossible (result anyref)
+ (local $val nullref)
+ ;; Require that typeof($val) <: nullref.
+ (array.get $sub
+ (local.get $val)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-set (type $0)
+ ;; CHECK-NEXT: (local $ref (ref null $super-mut))
+ ;; CHECK-NEXT: (local $val eqref)
+ ;; CHECK-NEXT: (array.set $super-mut
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-set
+ (local $ref (ref null $sub-mut))
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: (ref null $super-mut) and that typeof($val) <:
+ ;; eqref.
+ (array.set $sub-mut
+ (local.get $ref)
+ (i32.const 0)
+ (local.get $val)
+ )
+ )
+
+ ;; CHECK: (func $array-set-impossible (type $0)
+ ;; CHECK-NEXT: (local $ref nullref)
+ ;; CHECK-NEXT: (local $val anyref)
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-set-impossible
+ (local $ref nullref)
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: nullref and do not constrain $ref.
+ (array.set $sub-mut
+ (local.get $ref)
+ (i32.const 0)
+ (local.get $val)
+ )
+ )
+
+ ;; CHECK: (func $array-len (type $0)
+ ;; CHECK-NEXT: (local $ref arrayref)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (array.len
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-len
+ (local $ref (ref null $super))
+ (drop
+ ;; Require that typeof($ref) <: arrayref.
+ (array.len
+ (local.get $ref)
+ )
+ )
+ )
+
+ ;; CHECK: (func $array-copy-ref (type $0)
+ ;; CHECK-NEXT: (local $dest (ref null $super-mut))
+ ;; CHECK-NEXT: (local $src (ref null $super))
+ ;; CHECK-NEXT: (array.copy $super-mut $super
+ ;; CHECK-NEXT: (local.get $dest)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $src)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-copy-ref
+ (local $dest (ref null $sub-mut))
+ (local $src (ref null $sub))
+ ;; Require that typeof($dest) <: $super-mut and that typeof($src) <: $super.
+ (array.copy $sub-mut $sub
+ (local.get $dest)
+ (i32.const 0)
+ (local.get $src)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-copy-i8 (type $0)
+ ;; CHECK-NEXT: (local $dest (ref null $mut-bytes))
+ ;; CHECK-NEXT: (local $src (ref null $bytes))
+ ;; CHECK-NEXT: (array.copy $mut-bytes $bytes
+ ;; CHECK-NEXT: (local.get $dest)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $src)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-copy-i8
+ ;; Same as above, but now the copied element type is not a ref.
+ (local $dest (ref null $sub-mut-bytes))
+ (local $src (ref null $sub-bytes))
+ ;; Require that typeof($dest) <: $mut-bytes and that typeof($src) <: $bytes.
+ (array.copy $sub-mut-bytes $sub-bytes
+ (local.get $dest)
+ (i32.const 0)
+ (local.get $src)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-copy-impossible-dest (type $0)
+ ;; CHECK-NEXT: (local $dest nullref)
+ ;; CHECK-NEXT: (local $src anyref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $dest)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $src)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-copy-impossible-dest
+ ;; Same as above, but now the dest is bottom.
+ (local $dest nullref)
+ (local $src (ref null $sub))
+ ;; Require that typeof($dest) <: nullref but do not constrain $src.
+ (array.copy $sub-mut $sub
+ (local.get $dest)
+ (i32.const 0)
+ (local.get $src)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-copy-impossible-src (type $0)
+ ;; CHECK-NEXT: (local $dest anyref)
+ ;; CHECK-NEXT: (local $src nullref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $dest)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $src)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-copy-impossible-src
+ ;; Same as above, but now the src is bottom instead.
+ (local $dest (ref null $sub-mut))
+ (local $src nullref)
+ ;; Require that typeof($src) <: nullref but do not constrain $dest.
+ (array.copy $sub-mut $sub
+ (local.get $dest)
+ (i32.const 0)
+ (local.get $src)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-copy-impossible-both (type $0)
+ ;; CHECK-NEXT: (local $dest nullref)
+ ;; CHECK-NEXT: (local $src nullref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $dest)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $src)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-copy-impossible-both
+ ;; Same as above, but now both src and dest are bottom.
+ (local $dest nullref)
+ (local $src nullref)
+ ;; Do not constrain $src or $dest.
+ (array.copy $sub-mut $sub
+ (local.get $dest)
+ (i32.const 0)
+ (local.get $src)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-fill (type $0)
+ ;; CHECK-NEXT: (local $ref (ref null $super-mut))
+ ;; CHECK-NEXT: (local $val eqref)
+ ;; CHECK-NEXT: (array.fill $super-mut
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-fill
+ (local $ref (ref null $sub-mut))
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: (ref null $super-mut) and that typeof($val) <:
+ ;; eqref.
+ (array.fill $sub-mut
+ (local.get $ref)
+ (i32.const 0)
+ (local.get $val)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-fill-impossible (type $0)
+ ;; CHECK-NEXT: (local $ref nullref)
+ ;; CHECK-NEXT: (local $val anyref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (local.get $val)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-fill-impossible
+ (local $ref nullref)
+ (local $val i31ref)
+ ;; Require that typeof($ref) <: nullref, but do not constrain $val.
+ (array.fill $sub-mut
+ (local.get $ref)
+ (i32.const 0)
+ (local.get $val)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-init-data (type $0)
+ ;; CHECK-NEXT: (local $ref (ref null $mut-bytes))
+ ;; CHECK-NEXT: (array.init_data $mut-bytes $data
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-init-data
+ (local $ref (ref null $sub-mut-bytes))
+ ;; Require that typeof($ref) <: (ref null $mut-bytes).
+ (array.init_data $sub-mut-bytes $data
+ (local.get $ref)
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-init-data-impossible (type $0)
+ ;; CHECK-NEXT: (local $ref nullref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-init-data-impossible
+ (local $ref nullref)
+ ;; Require that typeof($ref) <: nullref.
+ (array.init_data $sub-mut-bytes $data
+ (local.get $ref)
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-init-elem (type $0)
+ ;; CHECK-NEXT: (local $ref (ref null $super-mut))
+ ;; CHECK-NEXT: (array.init_elem $super-mut $elem
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-init-elem
+ (local $ref (ref null $sub-mut))
+ ;; Require that typeof($ref) <: (ref null $super-mut).
+ (array.init_elem $sub-mut $elem
+ (local.get $ref)
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
+
+ ;; CHECK: (func $array-init-elem-impossible (type $0)
+ ;; CHECK-NEXT: (local $ref nullref)
+ ;; CHECK-NEXT: (block
+ ;; CHECK-NEXT: (local.get $ref)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: (i32.const 0)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $array-init-elem-impossible
+ (local $ref nullref)
+ ;; Require that typeof($ref) <: nullref.
+ (array.init_elem $sub-mut $elem
+ (local.get $ref)
+ (i32.const 0)
+ (i32.const 0)
+ (i32.const 0)
+ )
+ )
)