diff options
-rw-r--r-- | src/wasm/wasm-validator.cpp | 12 | ||||
-rw-r--r-- | test/lit/tail-call.wast | 78 | ||||
-rw-r--r-- | test/tail-call.wast | 11 |
3 files changed, 85 insertions, 16 deletions
diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index f492c7110..450a7b956 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -460,9 +460,9 @@ private: Type(Type::unreachable), curr, "return_call* should have unreachable type"); - shouldBeEqual( - getFunction()->getResults(), + shouldBeSubType( sig.results, + getFunction()->getResults(), curr, "return_call* callee return type must match caller return type"); } else { @@ -798,9 +798,11 @@ void FunctionValidator::visitCallIndirect(CallIndirect* curr) { if (curr->target->type != Type::unreachable) { auto* table = getModule()->getTableOrNull(curr->table); shouldBeTrue(!!table, curr, "call-indirect table must exist"); - shouldBeTrue(table->type.isFunction(), - curr, - "call-indirect table must be of function type."); + if (table) { + shouldBeTrue(table->type.isFunction(), + curr, + "call-indirect table must be of function type."); + } } validateCallParamsAndResult(curr, curr->sig); diff --git a/test/lit/tail-call.wast b/test/lit/tail-call.wast new file mode 100644 index 000000000..92dfdbb4e --- /dev/null +++ b/test/lit/tail-call.wast @@ -0,0 +1,78 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; Check that tail calls are parsed, validated, and printed correctly + +;; RUN: foreach %s %t wasm-opt -all -S -o - | filecheck %s +;; TODO: --nominal as well + +(module + + ;; CHECK: (type $void (func)) + (type $void (func)) + + ;; CHECK: (table $t 1 1 funcref) + (table $t 1 1 funcref) + + ;; CHECK: (elem $e (i32.const 0) $foo) + (elem $e (i32.const 0) $foo) + + ;; CHECK: (func $foo + ;; CHECK-NEXT: (return_call $bar) + ;; CHECK-NEXT: ) + (func $foo + (return_call $bar) + ) + + ;; CHECK: (func $bar + ;; CHECK-NEXT: (return_call_indirect $t (type $void) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $bar + (return_call_indirect (type $void) (i32.const 0)) + ) +) + +;; Check GC types and subtyping +(module + ;; CHECK: (type $return-B (func (result (ref $B)))) + (type $return-B (func (result (ref $B)))) + + ;; CHECK: (type $return-A (func (result (ref null $A)))) + (type $return-A (func (result (ref null $A)))) + + ;; CHECK: (type $A (struct (field i32))) + (type $A (struct i32)) + + ;; CHECK: (type $B (struct (field i32) (field i32))) + (type $B (struct i32 i32) (supertype $A)) + + ;; CHECK: (table $t 1 1 funcref) + (table $t 1 1 funcref) + + ;; CHECK: (elem $e (i32.const 0) $callee) + (elem $e (i32.const 0) $callee) + + ;; CHECK: (func $caller (result (ref null $A)) + ;; CHECK-NEXT: (return_call $callee) + ;; CHECK-NEXT: ) + (func $caller (type $return-A) + (return_call $callee) + ) + + ;; CHECK: (func $caller-indirect (result (ref $B)) + ;; CHECK-NEXT: (return_call_indirect $t (type $return-B) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $caller-indirect (type $return-B) + (return_call_indirect $t (type $return-B) (i32.const 0)) + ) + + ;; CHECK: (func $callee (result (ref $B)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $callee (type $return-B) + (unreachable) + ) +) diff --git a/test/tail-call.wast b/test/tail-call.wast deleted file mode 100644 index ceea1239e..000000000 --- a/test/tail-call.wast +++ /dev/null @@ -1,11 +0,0 @@ -(module - (type $void (func)) - (table 1 1 funcref) - (elem (i32.const 0) $foo) - (func $foo - (return_call $bar) - ) - (func $bar - (return_call_indirect (type $void) (i32.const 0)) - ) -)
\ No newline at end of file |