Source code
Revision control
Copy as Markdown
Other Tools
/* Copyright 2021 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// ./test/core/stack-switching/validation.wast
// ./test/core/stack-switching/validation.wast:8
let $0 = instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; nocont <: cont
(local.set \$x1 (local.get \$p2))
;; nocont <: \$ct1
(local.set \$x3 (local.get \$p2))
;; \$ct1 <: \$cont
(local.set \$x3 (local.get \$p3))
;; (ref \$ct1) <: (ref null \$cont)
(local.set \$x5 (local.get \$p3))
)
)`);
// ./test/core/stack-switching/validation.wast:40
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; cont </: nocont
(local.set \$p2 (local.get \$p1))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:66
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; \$ct1 </: nocont
(local.set \$p2 (local.get \$p3))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:92
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; \$cont </: \$ct1
(local.set \$p3 (local.get \$p1))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:118
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(param \$p4 (ref \$ct2))
(param \$p5 (ref null \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; (ref null \$ct1) </: (ref \$cont)
(local.set \$x3 (local.get \$p5))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:147
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test
(param \$p1 (ref cont))
(param \$p2 (ref nocont))
(param \$p3 (ref \$ct1))
(param \$p4 (ref \$ct2))
(param \$p5 (ref null \$ct1))
(local \$x1 (ref cont))
(local \$x2 (ref nocont))
(local \$x3 (ref \$ct1))
(local \$x4 (ref \$ct2))
(local \$x5 (ref null \$ct1))
;; (ref \$ct1) </: (ref \$ct2)
(local.set \$p4 (local.get \$p3))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:180
let $1 = instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i64 i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$test1
(param \$p_ct1 (ref null \$ct1))
(result (ref \$ct0))
;; cont.bind takes nullable ref, returns non-nullable one
(i32.const 123)
(local.get \$p_ct1)
(cont.bind \$ct1 \$ct0)
)
(func \$test2
(param \$p_ct2 (ref \$ct2))
(result (ref \$ct1))
;; cont.bind does not have to apply continuation fully
(i64.const 123)
(local.get \$p_ct2)
(cont.bind \$ct2 \$ct1)
)
(func \$test3
(param \$p_ct1 (ref \$ct1))
(result (ref \$ct1))
;; cont.bind can take same type twice, not actually apply anything
(local.get \$p_ct1)
(cont.bind \$ct1 \$ct1)
)
)`);
// ./test/core/stack-switching/validation.wast:223
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(func \$error
(param \$p_ft0 (ref \$ft0))
;; error: non-continuation type on cont.bind
(local.get \$p_ft0)
(cont.bind \$ft0 \$ft0)
(drop)
)
)`),
`non-continuation type`,
);
// ./test/core/stack-switching/validation.wast:244
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$error
(param \$p_ct1 (ref \$ct1))
;; cont.bind type mismatch: passing wrong kind of continuation.
;; This is actually just checking type-matching, not cont.bind specific.
(local.get \$p_ct1)
(cont.bind \$ct0 \$ct0)
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:265
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i64 i32) (result i32)))
(type \$ct2 (cont \$ft2))
(type \$ft1_alt (func (param i64) (result i32)))
(type \$ct1_alt (cont \$ft1_alt))
(func \$error
(param \$p_ct2 (ref \$ct2))
;; error: two continuation types not agreeing on arg types
(i64.const 123)
(local.get \$p_ct2)
(cont.bind \$ct2 \$ct1_alt)
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:293
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i64 i32) (result i32)))
(type \$ct2 (cont \$ft2))
(type \$ft1_alt (func (param i32) (result i64)))
(type \$ct1_alt (cont \$ft1_alt))
(func \$error
(param \$p_ct2 (ref \$ct2))
;; error: two continuation types not agreeing on return types
(i64.const 123)
(local.get \$p_ct2)
(cont.bind \$ct2 \$ct1_alt)
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:321
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$error
(param \$p_ct0 (ref \$ct0))
;; error: trying to go from 0 to 1 args
(local.get \$p_ct0)
(cont.bind \$ct0 \$ct1)
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:341
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$error
(param \$p_ct1 (ref \$ct1))
;; error: Insufficient arguments::
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(cont.bind \$ct1 \$ct0 (local.get \$p_ct1))
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:363
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (result i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$error
(param \$p_ct1 (ref \$ct1))
;; error: Too many arguments::
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(cont.bind \$ct1 \$ct0 (i32.const 123) (i32.const 123) (local.get \$p_ct1))
(drop)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:388
let $2 = instantiate(`(module
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32 i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$f1 (export "f1") (param i32) (result i32)
(i32.const 123)
)
(func \$drop_ct1 (param \$c (ref \$ct1)))
;; simple smoke test
(func \$test_good1 (param \$x (ref \$ft1)) (result (ref \$ct1))
(local.get \$x)
(cont.new \$ct1)
)
;; cont.new takes a nullable function
(func \$test_good2 (param \$x (ref null \$ft1)) (result (ref \$ct1))
(local.get \$x)
(cont.new \$ct1)
)
)`);
// ./test/core/stack-switching/validation.wast:416
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$bad (param \$x (ref null \$ct1)) (result (ref \$ct1))
(local.get \$x)
(cont.new \$ct1)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:432
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i32 i32) (result i32)))
(type \$ct2 (cont \$ft2))
(func \$drop_ct1 (param \$c (ref \$ct1)))
(func \$bad (param \$x (ref null \$ft2)) (result (ref \$ct1))
(local.get \$x)
(cont.new \$ct1)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:453
assert_invalid(
() => instantiate(`(module
(type \$ft1 (func (param i32) (result i32)))
(type \$ct1 (cont \$ft1))
(func \$bad (param \$x (ref null \$ct1))
(local.get \$x)
(cont.new \$ft1)
(drop)
)
)`),
`non-continuation type 0`,
);
// ./test/core/stack-switching/validation.wast:473
let $3 = instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param f32) (result f64)))
(type \$ct1 (cont \$ft1))
(type \$ft2 (func (param i64) (result f64)))
(type \$ct2 (cont \$ft2))
(type \$ft3 (func (param i32) (result f64)))
(type \$ct3 (cont \$ft3))
(tag \$t0)
(tag \$t1)
(tag \$t2 (param i32) (result i64))
(tag \$t3 (param i64) (result i32))
;; Multiple tags, all types handled correctly
(func \$test0 (param \$x (ref \$ct1)) (result f64)
(block \$handler0 (result i32 (ref \$ct2))
(block \$handler1 (result i64 (ref \$ct3))
(f32.const 1.23)
(local.get \$x)
(resume \$ct1 (on \$t2 \$handler0) (on \$t3 \$handler1))
(return)
)
(unreachable)
)
(unreachable)
)
;; Same as \$test0, but we provide two handlers for the same tag
(func \$test1 (param \$x (ref \$ct1)) (result f64)
(block \$handler0 (result i32 (ref \$ct2))
(block \$handler1 (result i32 (ref \$ct2))
(f32.const 1.23)
(local.get \$x)
(resume \$ct1 (on \$t2 \$handler0) (on \$t2 \$handler1))
(return)
)
(unreachable)
)
(unreachable)
)
;; resume takes a nullable reference
(func \$test2 (param \$x (ref null \$ct0))
(local.get \$x)
(resume \$ct0)
)
;; handler blocks take the continuation as nullable ref
(func \$test3 (param \$x (ref \$ct0))
(block \$handler (result (ref null \$ct0))
(local.get \$x)
(resume \$ct0 (on \$t0 \$handler))
(return)
)
(unreachable)
)
;; Nothing wrong with using the same handler block for multiple tags
(func \$test4 (param \$x (ref \$ct0))
(block \$handler (result (ref null \$ct0))
(local.get \$x)
(resume \$ct0 (on \$t0 \$handler) (on \$t1 \$handler))
(return)
)
(unreachable)
)
;; handler block can have params
(func \$test5 (param \$x (ref \$ct0))
(local.get \$x)
(block \$handler (param (ref \$ct0)) (result (ref \$ct0))
(resume \$ct0 (on \$t0 \$handler))
(return)
)
(unreachable)
)
)`);
// ./test/core/stack-switching/validation.wast:557
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
;;(tag \$t0)
(func \$error (param \$x (ref \$ct0))
(block \$handler (result (ref null \$ct0))
(local.get \$x)
(resume \$ct0 (on 0 \$handler))
(return)
)
(unreachable)
)
)`),
`unknown tag`,
);
// ./test/core/stack-switching/validation.wast:576
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(func \$error (param \$x (ref \$ct0))
(local.get \$x)
(resume \$ft0)
)
)`),
`non-continuation type`,
);
// ./test/core/stack-switching/validation.wast:590
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(tag \$t0)
(func \$test1 (param \$x (ref \$ct0))
(block \$handler (result (ref \$ft0))
(local.get \$x)
(resume \$ct0 (on \$t0 \$handler))
(return)
)
(unreachable)
)
)`),
`non-continuation type`,
);
// ./test/core/stack-switching/validation.wast:608
assert_invalid(
() => instantiate(`(module
(type \$ft (func (param i32)))
(type \$ct (cont \$ft))
(func \$error
(param \$p (ref \$ct))
;; error: Too many arguments::
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(resume \$ct (i32.const 123) (i32.const 123) (local.get \$p))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:624
assert_invalid(
() => instantiate(`(module
(type \$ft (func (param i32)))
(type \$ct (cont \$ft))
(func \$error
(param \$p (ref \$ct))
;; error: Too few arguments::
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(resume \$ct (local.get \$p))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:640
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func (param i32)))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i64)))
(type \$ct1 (cont \$ft1))
(func \$error
(param \$p (ref \$ct1))
;; error: Mismatch between annotation on resume and actual argument
;; This is really testing the general application of arguments to instructions.
(resume \$ct0 (i32.const 123) (local.get \$p))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:658
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(tag \$t (param i32))
(func \$error
(param \$p (ref \$ct0))
(block \$handler (result (ref \$ct0))
;; error: handler block has insufficient number of results
(local.get \$p)
(resume \$ct0 (on \$t \$handler))
(return)
)
(unreachable)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:679
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(tag \$t (param i32))
(func \$error
(param \$p (ref \$ct0))
(block \$handler (result i32 i32 (ref \$ct0))
;; error: handler block has too many results
(local.get \$p)
(resume \$ct0 (on \$t \$handler))
(return)
)
(unreachable)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:700
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(tag \$t (param i32))
(func \$error
(param \$p (ref \$ct0))
(block \$handler (result i64 (ref \$ct0))
;; error: type mismatch in non-continuation handler result type
(local.get \$p)
(resume \$ct0 (on \$t \$handler))
(return)
)
(unreachable)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:721
assert_invalid(
() => instantiate(`(module
(type \$ft0 (func))
(type \$ct0 (cont \$ft0))
(type \$ft1 (func (param i32)))
(type \$ct1 (cont \$ft1))
(tag \$t (param i32))
(func \$error
(param \$p (ref \$ct0))
(block \$handler (result i32 (ref \$ct1))
;; error: type mismatch in continuation handler result type
(local.get \$p)
(resume \$ct0 (on \$t \$handler))
(return)
)
(unreachable)
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:749
let $4 = instantiate(`(module
(tag \$t (param i64 i32) (result i32 i64))
(func \$test (result i32 i64)
(i64.const 123)
(i32.const 123)
(suspend \$t)
)
)`);
// ./test/core/stack-switching/validation.wast:760
assert_invalid(
() => instantiate(`(module
(tag \$t (param i64 i32) (result i32 i64))
(func \$test (result i32 i64)
;; error: Insufficient arguments::
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(suspend \$t (i64.const 123))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:775
assert_invalid(
() => instantiate(`(module
(tag \$t (param i32) (result i32 i64))
(func \$test (result i32 i64)
;; error: Too many arguments:
;; This is really testing the general application of arguments to instructions,
;; but trying to trick parsers of the folded form
(suspend \$t (i64.const 123) (i32.const 123))
)
)`),
`type mismatch`,
);
// ./test/core/stack-switching/validation.wast:790
assert_invalid(
() => instantiate(`(module
(func \$test
;; error: Tag does not exist
(suspend 0)
)
)`),
`unknown tag`,
);
// ./test/core/stack-switching/validation.wast:803
assert_invalid(
() => instantiate(`(module
(func (drop (ref.test contref (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:809
assert_invalid(
() => instantiate(`(module
(func (drop (ref.test nullcontref (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:815
assert_invalid(
() => instantiate(`(module
(type \$f (func))
(type \$c (cont \$f))
(func (drop (ref.test (ref \$c) (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:824
assert_invalid(
() => instantiate(`(module
(func (drop (ref.cast contref (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:830
assert_invalid(
() => instantiate(`(module
(func (drop (ref.cast nullcontref (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:836
assert_invalid(
() => instantiate(`(module
(type \$f (func))
(type \$c (cont \$f))
(func (drop (ref.cast (ref \$c) (unreachable))))
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:845
assert_invalid(
() => instantiate(`(module
(func
(block (result contref) (br_on_cast 0 contref contref (unreachable)))
(drop)
)
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:854
assert_invalid(
() => instantiate(`(module
(func
(block (result contref) (br_on_cast 0 nullcontref nullcontref (unreachable)))
(drop)
)
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:863
assert_invalid(
() => instantiate(`(module
(type \$f (func))
(type \$c (cont \$f))
(func
(block (result contref) (br_on_cast 0 (ref \$c) (ref \$c) (unreachable)))
(drop)
)
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:875
assert_invalid(
() => instantiate(`(module
(func
(block (result contref) (br_on_cast_fail 0 contref contref (unreachable)))
(drop)
)
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:884
assert_invalid(
() => instantiate(`(module
(func
(block (result contref) (br_on_cast_fail 0 nullcontref nullcontref (unreachable)))
(drop)
)
)`),
`invalid cast`,
);
// ./test/core/stack-switching/validation.wast:893
assert_invalid(
() => instantiate(`(module
(type \$f (func))
(type \$c (cont \$f))
(func
(block (result contref) (br_on_cast_fail 0 (ref \$c) (ref \$c) (unreachable)))
(drop)
)
)`),
`invalid cast`,
);