diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 5dc7ce054e..3d7ad79e7b 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -1911,10 +1911,21 @@ where } Handle::OnSwitch { tag } => { let tag_ty = self.tag_at(tag)?; - if !self.is_func_subtype( + // The tag's type must be *equivalent* to (not merely a + // subtype of) `[] -> [old results]`: the handler judgment + // has no subsumption rule, so `(on tu switch) : t*` together + // with the required `hdl : t2*` forces `t* = t2*`. Checking + // subtyping in both directions gives equivalence, and also + // pins the tag to zero parameters (via the param-length + // check inside `is_func_subtype`). + let tag_matches = self.is_func_subtype( (tag_ty.params(), tag_ty.results()), (&[], old_func_ty.results()), - ) { + ) && self.is_func_subtype( + (&[], old_func_ty.results()), + (tag_ty.params(), tag_ty.results()), + ); + if !tag_matches { bail!( self.offset, "type mismatch: switch tag does not match continuation" diff --git a/tests/cli/stack-switching/validate-switch-label.wast b/tests/cli/stack-switching/validate-switch-label.wast index 74917b7512..3ee47c7b80 100644 --- a/tests/cli/stack-switching/validate-switch-label.wast +++ b/tests/cli/stack-switching/validate-switch-label.wast @@ -83,11 +83,32 @@ ) "type mismatch: switch tag does not match continuation") +;; The switch tag's results must be *equivalent* to the continuation's results, +;; not merely a subtype. Here the tag results `[nullfuncref]` are a strict +;; subtype of the continuation results `[funcref]`, so this must be rejected. +(assert_invalid + (module + (type $ft (func (result funcref))) + (type $ct (cont $ft)) + + (type $tag_ft (func (result nullfuncref))) + (tag $t (type $tag_ft)) + + (func + block $label + (resume $ct (on $t switch) (ref.null $ct)) + unreachable + end + ) + ) + "type mismatch: switch tag does not match continuation") + +;; Equivalent reference-type results (both `[funcref]`) are accepted. (module (type $ft (func (result funcref))) (type $ct (cont $ft)) - (type $tag_ft (func (result nullfuncref))) + (type $tag_ft (func (result funcref))) (tag $t (type $tag_ft)) (func diff --git a/tests/snapshots/cli/stack-switching/validate-switch-label.wast.json b/tests/snapshots/cli/stack-switching/validate-switch-label.wast.json index ed496e7cfe..db59137f2c 100644 --- a/tests/snapshots/cli/stack-switching/validate-switch-label.wast.json +++ b/tests/snapshots/cli/stack-switching/validate-switch-label.wast.json @@ -36,9 +36,16 @@ "text": "type mismatch: switch tag does not match continuation" }, { - "type": "module", - "line": 86, + "type": "assert_invalid", + "line": 90, "filename": "validate-switch-label.5.wasm", + "module_type": "binary", + "text": "type mismatch: switch tag does not match continuation" + }, + { + "type": "module", + "line": 107, + "filename": "validate-switch-label.6.wasm", "module_type": "binary" } ] diff --git a/tests/snapshots/cli/stack-switching/validate-switch-label.wast/5.print b/tests/snapshots/cli/stack-switching/validate-switch-label.wast/6.print similarity index 68% rename from tests/snapshots/cli/stack-switching/validate-switch-label.wast/5.print rename to tests/snapshots/cli/stack-switching/validate-switch-label.wast/6.print index 3a71bb73e7..210c1a057a 100644 --- a/tests/snapshots/cli/stack-switching/validate-switch-label.wast/5.print +++ b/tests/snapshots/cli/stack-switching/validate-switch-label.wast/6.print @@ -1,9 +1,9 @@ (module (type $ft (;0;) (func (result funcref))) (type $ct (;1;) (cont $ft)) - (type $tag_ft (;2;) (func (result nullfuncref))) + (type $tag_ft (;2;) (func (result funcref))) (type (;3;) (func)) - (tag $t (;0;) (type $tag_ft) (result nullfuncref)) + (tag $t (;0;) (type $tag_ft) (result funcref)) (func (;0;) (type 3) block $label ref.null $ct