summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-08-21 11:45:24 -0700
committerGitHub <noreply@github.com>2023-08-21 11:45:24 -0700
commit4672c533985e8f2c9a88dec616aa3d9b95deb63e (patch)
tree2a78580977dec80e3f56b54debc67b48e064aa28 /test
parentb41ec7cb488481e5b1a57fc7203e9c0bc7331bbd (diff)
downloadbinaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.tar.gz
binaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.tar.bz2
binaryen-4672c533985e8f2c9a88dec616aa3d9b95deb63e.zip
Fix finalization of call_ref to handle refined target types (#5883)
Previously CallRef::finalize() would never update the type of the CallRef, even if the type of the call target had been refined to give a more precise result type. Besides unnecessarily losing type information, this could also lead to validation errors, since the validator checks that the type of CallRef matches the result type of the target signature. Fix the bug by updating CallRef's type based on its target signature in CallRef::finalize() and add a test that depends on this refinalization.
Diffstat (limited to 'test')
-rw-r--r--test/lit/passes/local-subtyping.wast70
1 files changed, 70 insertions, 0 deletions
diff --git a/test/lit/passes/local-subtyping.wast b/test/lit/passes/local-subtyping.wast
index 2d6e2fb05..034606cb0 100644
--- a/test/lit/passes/local-subtyping.wast
+++ b/test/lit/passes/local-subtyping.wast
@@ -14,6 +14,11 @@
(type $array (array_subtype i8 data))
+ ;; CHECK: (type $ret-any (func (result anyref)))
+ (type $ret-any (sub (func (result anyref))))
+ ;; CHECK: (type $ret-i31 (sub $ret-any (func (result i31ref))))
+ (type $ret-i31 (sub $ret-any (func (result i31ref))))
+
;; CHECK: (import "out" "i32" (func $i32 (type $none_=>_i32) (result i32)))
(import "out" "i32" (func $i32 (result i32)))
;; CHECK: (import "out" "i64" (func $i64 (type $none_=>_i64) (result i64)))
@@ -229,6 +234,71 @@
)
)
+ ;; CHECK: (func $multiple-iterations-refinalize-call-ref (type $none_=>_none)
+ ;; CHECK-NEXT: (local $f (ref $ret-i31))
+ ;; CHECK-NEXT: (local $x i31ref)
+ ;; CHECK-NEXT: (local.set $f
+ ;; CHECK-NEXT: (ref.func $ret-i31)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (call_ref $ret-i31
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $multiple-iterations-refinalize-call-ref
+ (local $f (ref null $ret-any))
+ (local $x (anyref))
+ (local.set $f
+ (ref.func $ret-i31)
+ )
+ (local.set $x
+ ;; After $f is refined to hold $ret-i31 and the call_ref is refinalized,
+ ;; we will be able to refine $x to i31.
+ (call_ref $ret-any
+ (local.get $f)
+ )
+ )
+ )
+
+ ;; CHECK: (func $multiple-iterations-refinalize-call-ref-bottom (type $none_=>_none)
+ ;; CHECK-NEXT: (local $f nullfuncref)
+ ;; CHECK-NEXT: (local $x anyref)
+ ;; CHECK-NEXT: (local.set $f
+ ;; CHECK-NEXT: (ref.null nofunc)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (local.set $x
+ ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (local.get $f)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $multiple-iterations-refinalize-call-ref-bottom
+ (local $f (ref null $ret-any))
+ (local $x (anyref))
+ ;; Same as above, but now we refine $f to nullfuncref. Check that we don't crash.
+ (local.set $f
+ (ref.null nofunc)
+ )
+ (local.set $x
+ ;; We can no longer refine $x because there is no result type we can use
+ ;; after refining $f.
+ (call_ref $ret-any
+ (local.get $f)
+ )
+ )
+ )
+
+ ;; CHECK: (func $ret-i31 (type $ret-i31) (result i31ref)
+ ;; CHECK-NEXT: (unreachable)
+ ;; CHECK-NEXT: )
+ (func $ret-i31 (type $ret-i31) (result i31ref)
+ (unreachable)
+ )
+
;; CHECK: (func $nondefaultable (type $none_=>_none)
;; CHECK-NEXT: (local $x (funcref funcref))
;; CHECK-NEXT: (local.set $x