summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/binary-reader-ast.c26
-rw-r--r--src/binary-reader-interpreter.c569
-rw-r--r--src/common.h9
-rw-r--r--src/type-checker.c524
-rw-r--r--src/type-checker.h100
-rw-r--r--src/validator.c481
-rw-r--r--test/interp/if-then-br.txt29
-rw-r--r--test/parse/expr/bad-binary-one-expr.txt6
-rw-r--r--test/parse/expr/bad-br-bad-depth.txt4
-rw-r--r--test/parse/expr/bad-br-defined-later.txt4
-rw-r--r--test/parse/expr/bad-br-undefined.txt4
-rw-r--r--test/parse/expr/bad-brtable-bad-depth.txt4
-rw-r--r--test/parse/expr/bad-compare-one-expr.txt6
-rw-r--r--test/parse/expr/bad-getglobal-name-undefined.txt8
-rw-r--r--test/parse/expr/bad-getglobal-undefined.txt11
-rw-r--r--test/parse/expr/bad-getlocal-undefined.txt11
-rw-r--r--test/parse/func/bad-sig-result-type-mismatch.txt5
-rw-r--r--test/parse/func/bad-sig-result-type-not-void.txt5
-rw-r--r--test/regress/regress-5.txt6
-rw-r--r--test/spec/block.txt14
-rw-r--r--test/spec/br.txt18
-rw-r--r--test/spec/br_if.txt10
-rw-r--r--test/spec/br_table.txt16
-rw-r--r--test/spec/call.txt6
-rw-r--r--test/spec/call_indirect.txt6
-rw-r--r--test/spec/func.txt2
-rw-r--r--test/spec/labels.txt4
-rw-r--r--test/spec/loop.txt2
-rw-r--r--test/spec/switch.txt2
-rw-r--r--test/spec/typecheck.txt77
-rw-r--r--test/spec/unreached-invalid.txt303
-rw-r--r--test/typecheck/bad-binary-type-mismatch-1.txt2
-rw-r--r--test/typecheck/bad-binary-type-mismatch-2.txt2
-rw-r--r--test/typecheck/bad-br-multi-type.txt16
-rw-r--r--test/typecheck/bad-brtable-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-call-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-callimport-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-callindirect-func-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-callindirect-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-cast-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-compare-type-mismatch-1.txt2
-rw-r--r--test/typecheck/bad-compare-type-mismatch-2.txt2
-rw-r--r--test/typecheck/bad-convert-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-expr-if.txt3
-rw-r--r--test/typecheck/bad-function-result-type-mismatch.txt6
-rw-r--r--test/typecheck/bad-grow-memory-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-if-condition-type-mismatch.txt15
-rw-r--r--test/typecheck/bad-if-type-mismatch.txt14
-rw-r--r--test/typecheck/bad-if-value-void.txt11
-rw-r--r--test/typecheck/bad-label-multi-type.txt22
-rw-r--r--test/typecheck/bad-load-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-nested-br.txt9
-rw-r--r--test/typecheck/bad-return-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-select-cond.txt2
-rw-r--r--test/typecheck/bad-select-value0.txt2
-rw-r--r--test/typecheck/bad-select-value1.txt2
-rw-r--r--test/typecheck/bad-setlocal-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-store-index-type-mismatch.txt2
-rw-r--r--test/typecheck/bad-unary-type-mismatch.txt2
m---------third_party/testsuite0
61 files changed, 1397 insertions, 1013 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4f546d42..c74db485 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -205,7 +205,9 @@ add_library(libwabt STATIC
src/ast-parser-lexer-shared.c
${AST_LEXER_GEN_C}
${AST_PARSER_GEN_C}
+ src/type-checker.c
src/validator.c
+
src/binary-reader.c
src/binary-writer.c
src/binary-writer-spec.c
diff --git a/src/binary-reader-ast.c b/src/binary-reader-ast.c
index 9ab3c7bc..956d2be1 100644
--- a/src/binary-reader-ast.c
+++ b/src/binary-reader-ast.c
@@ -33,16 +33,8 @@
return WABT_ERROR; \
} while (0)
-typedef enum LabelType {
- LABEL_TYPE_FUNC,
- LABEL_TYPE_BLOCK,
- LABEL_TYPE_LOOP,
- LABEL_TYPE_IF,
- LABEL_TYPE_ELSE,
-} LabelType;
-
typedef struct LabelNode {
- LabelType label_type;
+ WabtLabelType label_type;
WabtExpr** first;
WabtExpr* last;
} LabelNode;
@@ -67,7 +59,9 @@ static void WABT_PRINTF_FORMAT(2, 3)
handle_error(ctx, WABT_UNKNOWN_OFFSET, buffer);
}
-static void push_label(Context* ctx, LabelType label_type, WabtExpr** first) {
+static void push_label(Context* ctx,
+ WabtLabelType label_type,
+ WabtExpr** first) {
LabelNode label;
label.label_type = label_type;
label.first = first;
@@ -484,7 +478,7 @@ static WabtResult begin_function_body(WabtBinaryReaderContext* context,
Context* ctx = context->user_data;
assert(index < ctx->module->funcs.size);
ctx->current_func = ctx->module->funcs.data[index];
- push_label(ctx, LABEL_TYPE_FUNC, &ctx->current_func->first_expr);
+ push_label(ctx, WABT_LABEL_TYPE_FUNC, &ctx->current_func->first_expr);
return WABT_OK;
}
@@ -523,7 +517,7 @@ static WabtResult on_block_expr(uint32_t num_types,
src.data = sig_types;
wabt_extend_types(ctx->allocator, &expr->block.sig, &src);
append_expr(ctx, expr);
- push_label(ctx, LABEL_TYPE_BLOCK, &expr->block.first);
+ push_label(ctx, WABT_LABEL_TYPE_BLOCK, &expr->block.first);
return WABT_OK;
}
@@ -610,7 +604,7 @@ static WabtResult on_else_expr(void* user_data) {
Context* ctx = user_data;
LabelNode* label;
CHECK_RESULT(top_label(ctx, &label));
- if (label->label_type != LABEL_TYPE_IF) {
+ if (label->label_type != WABT_LABEL_TYPE_IF) {
print_error(ctx, "else expression without matching if");
return WABT_ERROR;
}
@@ -619,7 +613,7 @@ static WabtResult on_else_expr(void* user_data) {
CHECK_RESULT(get_label_at(ctx, &parent_label, 1));
assert(parent_label->last->type == WABT_EXPR_TYPE_IF);
- label->label_type = LABEL_TYPE_ELSE;
+ label->label_type = WABT_LABEL_TYPE_ELSE;
label->first = &parent_label->last->if_.false_;
label->last = NULL;
return WABT_OK;
@@ -695,7 +689,7 @@ static WabtResult on_if_expr(uint32_t num_types,
src.data = sig_types;
wabt_extend_types(ctx->allocator, &expr->if_.true_.sig, &src);
append_expr(ctx, expr);
- push_label(ctx, LABEL_TYPE_IF, &expr->if_.true_.first);
+ push_label(ctx, WABT_LABEL_TYPE_IF, &expr->if_.true_.first);
return WABT_OK;
}
@@ -722,7 +716,7 @@ static WabtResult on_loop_expr(uint32_t num_types,
src.data = sig_types;
wabt_extend_types(ctx->allocator, &expr->loop.sig, &src);
append_expr(ctx, expr);
- push_label(ctx, LABEL_TYPE_LOOP, &expr->loop.first);
+ push_label(ctx, WABT_LABEL_TYPE_LOOP, &expr->loop.first);
return WABT_OK;
}
diff --git a/src/binary-reader-interpreter.c b/src/binary-reader-interpreter.c
index c27e440b..9a44f7a8 100644
--- a/src/binary-reader-interpreter.c
+++ b/src/binary-reader-interpreter.c
@@ -24,31 +24,15 @@
#include "allocator.h"
#include "binary-reader.h"
#include "interpreter.h"
+#include "type-checker.h"
#include "writer.h"
-#define LOG 0
-
-#if LOG
-#define LOGF(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define LOGF(...) (void)0
-#endif
-
#define CHECK_RESULT(expr) \
do { \
if (WABT_FAILED(expr)) \
return WABT_ERROR; \
} while (0)
-#define CHECK_DEPTH(ctx, depth) \
- do { \
- if ((depth) >= (ctx)->label_stack.size) { \
- print_error((ctx), "invalid depth: %d (max %" PRIzd ")", (depth), \
- ((ctx)->label_stack.size)); \
- return WABT_ERROR; \
- } \
- } while (0)
-
#define CHECK_LOCAL(ctx, local_index) \
do { \
uint32_t max_local_index = \
@@ -70,30 +54,11 @@
} \
} while (0)
-#define RETURN_IF_TOP_TYPE_IS_ANY(ctx) \
- if (top_type_is_any(ctx)) \
- return
-
-#define RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx) \
- if (top_type_is_any(ctx)) \
- return WABT_OK
-
typedef uint32_t Uint32;
WABT_DEFINE_VECTOR(uint32, Uint32);
WABT_DEFINE_VECTOR(uint32_vector, Uint32Vector);
-typedef enum LabelType {
- LABEL_TYPE_FUNC,
- LABEL_TYPE_BLOCK,
- LABEL_TYPE_LOOP,
- LABEL_TYPE_IF,
- LABEL_TYPE_ELSE,
-} LabelType;
-
typedef struct Label {
- LabelType label_type;
- WabtTypeVector sig;
- uint32_t type_stack_limit;
uint32_t offset; /* branch location in the istream */
uint32_t fixup_offset;
} Label;
@@ -107,11 +72,10 @@ typedef struct Context {
WabtInterpreterEnvironment* env;
WabtInterpreterModule* module;
WabtInterpreterFunc* current_func;
- WabtTypeVector type_stack;
+ WabtTypeChecker typechecker;
LabelVector label_stack;
Uint32VectorVector func_fixups;
Uint32VectorVector depth_fixups;
- uint32_t depth;
WabtMemoryWriter istream_writer;
uint32_t istream_offset;
/* mappings from module index space to env index space; this won't just be a
@@ -133,11 +97,11 @@ typedef struct Context {
static Label* get_label(Context* ctx, uint32_t depth) {
assert(depth < ctx->label_stack.size);
- return &ctx->label_stack.data[depth];
+ return &ctx->label_stack.data[ctx->label_stack.size - depth - 1];
}
static Label* top_label(Context* ctx) {
- return get_label(ctx, ctx->label_stack.size - 1);
+ return get_label(ctx, 0);
}
static void handle_error(uint32_t offset, const char* message, Context* ctx) {
@@ -153,6 +117,11 @@ static void WABT_PRINTF_FORMAT(2, 3)
handle_error(WABT_INVALID_OFFSET, buffer, ctx);
}
+static void on_typechecker_error(const char* msg, void* user_data) {
+ Context* ctx = user_data;
+ print_error(ctx, "%s", msg);
+}
+
static uint32_t translate_sig_index_to_env(Context* ctx, uint32_t sig_index) {
assert(sig_index < ctx->sig_index_mapping.size);
return ctx->sig_index_mapping.data[sig_index];
@@ -226,11 +195,6 @@ static WabtType get_local_type_by_index(WabtInterpreterFunc* func,
return func->defined.param_and_local_types.data[local_index];
}
-static uint32_t translate_local_index(Context* ctx, uint32_t local_index) {
- assert(local_index < ctx->type_stack.size);
- return ctx->type_stack.size - local_index;
-}
-
static uint32_t get_istream_offset(Context* ctx) {
return ctx->istream_offset;
}
@@ -274,10 +238,8 @@ static WabtResult emit_drop_keep(Context* ctx, uint32_t drop, uint8_t keep) {
assert(keep <= 1);
if (drop > 0) {
if (drop == 1 && keep == 0) {
- LOGF("%3" PRIzd ": drop\n", ctx->type_stack.size);
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_DROP));
} else {
- LOGF("%3" PRIzd ": drop_keep %u %u\n", ctx->type_stack.size, drop, keep);
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_DROP_KEEP));
CHECK_RESULT(emit_i32(ctx, drop));
CHECK_RESULT(emit_i8(ctx, keep));
@@ -300,41 +262,68 @@ static WabtResult append_fixup(Context* ctx,
static WabtResult emit_br_offset(Context* ctx,
uint32_t depth,
uint32_t offset) {
- if (offset == WABT_INVALID_OFFSET)
- CHECK_RESULT(append_fixup(ctx, &ctx->depth_fixups, depth));
+ if (offset == WABT_INVALID_OFFSET) {
+ /* depth_fixups stores the depth counting up from zero, where zero is the
+ * top-level function scope. */
+ depth = ctx->label_stack.size - 1 - depth;
+ CHECK_RESULT(
+ append_fixup(ctx, &ctx->depth_fixups, depth));
+ }
CHECK_RESULT(emit_i32(ctx, offset));
return WABT_OK;
}
-static uint32_t get_label_br_arity(Label* label) {
- return label->label_type != LABEL_TYPE_LOOP ? label->sig.size : 0;
+static WabtResult get_br_drop_keep_count(Context* ctx,
+ uint32_t depth,
+ uint32_t* out_drop_count,
+ uint32_t* out_keep_count) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(wabt_typechecker_get_label(&ctx->typechecker, depth, &label));
+ *out_keep_count =
+ label->label_type != WABT_LABEL_TYPE_LOOP ? label->sig.size : 0;
+ if (wabt_typechecker_is_unreachable(&ctx->typechecker)) {
+ *out_drop_count = 0;
+ } else {
+ *out_drop_count =
+ (ctx->typechecker.type_stack.size - label->type_stack_limit) -
+ *out_keep_count;
+ }
+ return WABT_OK;
+}
+
+static WabtResult get_return_drop_keep_count(Context* ctx,
+ uint32_t* out_drop_count,
+ uint32_t* out_keep_count) {
+ if (WABT_FAILED(get_br_drop_keep_count(ctx, ctx->label_stack.size - 1,
+ out_drop_count, out_keep_count))) {
+ return WABT_ERROR;
+ }
+
+ *out_drop_count += ctx->current_func->defined.param_and_local_types.size;
+ return WABT_OK;
}
-static WabtResult emit_br(Context* ctx, uint32_t depth) {
- Label* label = get_label(ctx, depth);
- uint32_t arity = get_label_br_arity(label);
- assert(ctx->type_stack.size >= label->type_stack_limit + arity);
- uint32_t drop_count =
- (ctx->type_stack.size - label->type_stack_limit) - arity;
- CHECK_RESULT(emit_drop_keep(ctx, drop_count, arity));
+static WabtResult emit_br(Context* ctx,
+ uint32_t depth,
+ uint32_t drop_count,
+ uint32_t keep_count) {
+ CHECK_RESULT(emit_drop_keep(ctx, drop_count, keep_count));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR));
- CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
+ CHECK_RESULT(emit_br_offset(ctx, depth, get_label(ctx, depth)->offset));
return WABT_OK;
}
static WabtResult emit_br_table_offset(Context* ctx, uint32_t depth) {
- Label* label = get_label(ctx, depth);
- uint32_t arity = get_label_br_arity(label);
- assert(ctx->type_stack.size >= label->type_stack_limit + arity);
- uint32_t drop_count =
- (ctx->type_stack.size - label->type_stack_limit) - arity;
- CHECK_RESULT(emit_br_offset(ctx, depth, label->offset));
+ uint32_t drop_count, keep_count;
+ CHECK_RESULT(get_br_drop_keep_count(ctx, depth, &drop_count, &keep_count));
+ CHECK_RESULT(emit_br_offset(ctx, depth, get_label(ctx, depth)->offset));
CHECK_RESULT(emit_i32(ctx, drop_count));
- CHECK_RESULT(emit_i8(ctx, arity));
+ CHECK_RESULT(emit_i8(ctx, keep_count));
return WABT_OK;
}
-static WabtResult fixup_top_label(Context* ctx, uint32_t offset) {
+static WabtResult fixup_top_label(Context* ctx) {
+ uint32_t offset = get_istream_offset(ctx);
uint32_t top = ctx->label_stack.size - 1;
if (top >= ctx->depth_fixups.size) {
/* nothing to fixup */
@@ -1002,33 +991,13 @@ static WabtResult on_data_segment_data(uint32_t index,
return WABT_OK;
}
-static uint32_t translate_depth(Context* ctx, uint32_t depth) {
- assert(depth < ctx->label_stack.size);
- return ctx->label_stack.size - 1 - depth;
-}
-
-static void push_label(Context* ctx,
- LabelType label_type,
- const WabtTypeVector* sig,
- uint32_t offset,
- uint32_t fixup_offset) {
+static void push_label(Context* ctx, uint32_t offset, uint32_t fixup_offset) {
Label* label = wabt_append_label(ctx->allocator, &ctx->label_stack);
- label->label_type = label_type;
- wabt_extend_types(ctx->allocator, &label->sig, sig);
- label->type_stack_limit = ctx->type_stack.size;
label->offset = offset;
label->fixup_offset = fixup_offset;
- LOGF(" : +depth %" PRIzd "\n", ctx->label_stack.size - 1);
-}
-
-static void wabt_destroy_label(WabtAllocator* allocator, Label* label) {
- wabt_destroy_type_vector(allocator, &label->sig);
}
static void pop_label(Context* ctx) {
- LOGF(" : -depth %" PRIzd "\n", ctx->label_stack.size - 1);
- Label* label = top_label(ctx);
- wabt_destroy_label(ctx->allocator, label);
ctx->label_stack.size--;
/* reduce the depth_fixups stack as well, but it may be smaller than
* label_stack so only do it conditionally. */
@@ -1042,180 +1011,6 @@ static void pop_label(Context* ctx) {
}
}
-static WabtType top_type(Context* ctx) {
- Label* label = top_label(ctx);
- WABT_USE(label);
- assert(ctx->type_stack.size > label->type_stack_limit);
- return ctx->type_stack.data[ctx->type_stack.size - 1];
-}
-
-static WabtBool top_type_is_any(Context* ctx) {
- if (ctx->type_stack.size >
- ctx->current_func->defined.param_and_local_types.size) {
- WabtType top_type = ctx->type_stack.data[ctx->type_stack.size - 1];
- if (top_type == WABT_TYPE_ANY)
- return WABT_TRUE;
- }
- return WABT_FALSE;
-}
-
-/* TODO(binji): share a lot of the type-checking code w/ wabt-ast-checker.c */
-/* TODO(binji): flip actual + expected types, to match wabt-ast-checker.c */
-static size_t type_stack_limit(Context* ctx) {
- return top_label(ctx)->type_stack_limit;
-}
-
-static WabtResult check_type_stack_limit(Context* ctx,
- size_t expected,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- size_t limit = type_stack_limit(ctx);
- size_t avail = ctx->type_stack.size - limit;
- if (expected > avail) {
- print_error(ctx, "type stack size too small at %s. got %" PRIzd
- ", expected at least %" PRIzd,
- desc, avail, expected);
- return WABT_ERROR;
- }
- return WABT_OK;
-}
-
-static WabtResult check_type_stack_limit_exact(Context* ctx,
- size_t expected,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- size_t limit = type_stack_limit(ctx);
- size_t avail = ctx->type_stack.size - limit;
- if (expected != avail) {
- print_error(ctx, "type stack at end of %s is %" PRIzd ". expected %" PRIzd,
- desc, avail, expected);
- return WABT_ERROR;
- }
- return WABT_OK;
-}
-
-static void reset_type_stack_to_limit(Context* ctx) {
- ctx->type_stack.size = type_stack_limit(ctx);
-}
-
-static WabtResult check_type(Context* ctx,
- WabtType expected,
- WabtType actual,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- if (expected != actual) {
- print_error(ctx, "type mismatch in %s, expected %s but got %s.", desc,
- wabt_get_type_name(expected), wabt_get_type_name(actual));
- return WABT_ERROR;
- }
- return WABT_OK;
-}
-
-static WabtResult check_n_types(Context* ctx,
- const WabtTypeVector* expected,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- CHECK_RESULT(check_type_stack_limit(ctx, expected->size, desc));
- /* check the top of the type stack, with values pushed in reverse, against
- * the expected type list; for example, if:
- * expected = [i32, f32, i32, f64]
- * then
- * type_stack must be [ ..., f64, i32, f32, i32] */
- size_t i;
- for (i = 0; i < expected->size; ++i) {
- WabtType actual =
- ctx->type_stack.data[ctx->type_stack.size - expected->size + i];
- CHECK_RESULT(
- check_type(ctx, expected->data[expected->size - i - 1], actual, desc));
- }
- return WABT_OK;
-}
-
-static WabtType pop_type(Context* ctx) {
- WabtType type = top_type(ctx);
- if (type != WABT_TYPE_ANY) {
- LOGF("%3" PRIzd "->%3" PRIzd ": pop %s\n", ctx->type_stack.size,
- ctx->type_stack.size - 1, wabt_get_type_name(type));
- ctx->type_stack.size--;
- }
- return type;
-}
-
-static void push_type(Context* ctx, WabtType type) {
- RETURN_IF_TOP_TYPE_IS_ANY(ctx);
- if (type != WABT_TYPE_VOID) {
- LOGF("%3" PRIzd "->%3" PRIzd ": push %s\n", ctx->type_stack.size,
- ctx->type_stack.size + 1, wabt_get_type_name(type));
- wabt_append_type_value(ctx->allocator, &ctx->type_stack, &type);
- }
-}
-
-static void push_types(Context* ctx, const WabtTypeVector* types) {
- RETURN_IF_TOP_TYPE_IS_ANY(ctx);
- size_t i;
- for (i = 0; i < types->size; ++i)
- push_type(ctx, types->data[i]);
-}
-
-static WabtResult pop_and_check_1_type(Context* ctx,
- WabtType expected,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, 1, desc))) {
- WabtType actual = pop_type(ctx);
- CHECK_RESULT(check_type(ctx, expected, actual, desc));
- return WABT_OK;
- }
- return WABT_ERROR;
-}
-
-static WabtResult pop_and_check_2_types(Context* ctx,
- WabtType expected1,
- WabtType expected2,
- const char* desc) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, 2, desc))) {
- WabtType actual2 = pop_type(ctx);
- WabtType actual1 = pop_type(ctx);
- CHECK_RESULT(check_type(ctx, expected1, actual1, desc));
- CHECK_RESULT(check_type(ctx, expected2, actual2, desc));
- return WABT_OK;
- }
- return WABT_ERROR;
-}
-
-static WabtResult check_opcode1(Context* ctx, WabtOpcode opcode) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- CHECK_RESULT(pop_and_check_1_type(ctx, wabt_get_opcode_param_type_1(opcode),
- wabt_get_opcode_name(opcode)));
- push_type(ctx, wabt_get_opcode_result_type(opcode));
- return WABT_OK;
-}
-
-static WabtResult check_opcode2(Context* ctx, WabtOpcode opcode) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- CHECK_RESULT(pop_and_check_2_types(ctx, wabt_get_opcode_param_type_1(opcode),
- wabt_get_opcode_param_type_2(opcode),
- wabt_get_opcode_name(opcode)));
- push_type(ctx, wabt_get_opcode_result_type(opcode));
- return WABT_OK;
-}
-
-static WabtResult drop_types_for_return(Context* ctx, uint32_t arity) {
- RETURN_OK_IF_TOP_TYPE_IS_ANY(ctx);
- /* drop the locals and params, but keep the return value, if any. */
- if (ctx->type_stack.size >= arity) {
- uint32_t drop_count = ctx->type_stack.size - arity;
- CHECK_RESULT(emit_drop_keep(ctx, drop_count, arity));
- } else {
- /* it is possible for the size of the type stack to be smaller than the
- * return arity if the last instruction of the function is
- * return. In that case the type stack should be empty */
- assert(ctx->type_stack.size == 0);
- }
- return WABT_OK;
-}
-
static WabtResult begin_function_body(WabtBinaryReaderContext* context,
uint32_t index) {
Context* ctx = context->user_data;
@@ -1230,9 +1025,7 @@ static WabtResult begin_function_body(WabtBinaryReaderContext* context,
ctx->current_func = func;
ctx->depth_fixups.size = 0;
- ctx->type_stack.size = 0;
ctx->label_stack.size = 0;
- ctx->depth = 0;
/* fixup function references */
uint32_t defined_index = translate_module_func_index_to_defined(ctx, index);
@@ -1243,43 +1036,28 @@ static WabtResult begin_function_body(WabtBinaryReaderContext* context,
/* append param types */
for (i = 0; i < sig->param_types.size; ++i) {
- WabtType type = sig->param_types.data[i];
wabt_append_type_value(ctx->allocator, &func->defined.param_and_local_types,
- &type);
- wabt_append_type_value(ctx->allocator, &ctx->type_stack, &type);
+ &sig->param_types.data[i]);
}
+ CHECK_RESULT(
+ wabt_typechecker_begin_function(&ctx->typechecker, &sig->result_types));
+
/* push implicit func label (equivalent to return) */
- push_label(ctx, LABEL_TYPE_FUNC, &sig->result_types, WABT_INVALID_OFFSET,
- WABT_INVALID_OFFSET);
+ push_label(ctx, WABT_INVALID_OFFSET, WABT_INVALID_OFFSET);
return WABT_OK;
}
static WabtResult end_function_body(uint32_t index, void* user_data) {
Context* ctx = user_data;
- Label* label = top_label(ctx);
- if (!label || label->label_type != LABEL_TYPE_FUNC) {
- print_error(ctx, "unexpected function end");
- return WABT_ERROR;
- }
-
- CHECK_RESULT(check_n_types(ctx, &label->sig, "implicit return"));
- CHECK_RESULT(check_type_stack_limit_exact(ctx, label->sig.size, "func"));
- fixup_top_label(ctx, get_istream_offset(ctx));
- if (top_type_is_any(ctx)) {
- /* if the top type is any it means that this code is unreachable, at least
- * from the normal fallthrough, though it's possible that this code was
- * reached by branching to the implicit function label. If so, we have
- * already validated that the stack at that location, so we just need to
- * reset it to that state. */
- reset_type_stack_to_limit(ctx);
- push_types(ctx, &label->sig);
- }
- CHECK_RESULT(drop_types_for_return(ctx, label->sig.size));
+ fixup_top_label(ctx);
+ uint32_t drop_count, keep_count;
+ CHECK_RESULT(get_return_drop_keep_count(ctx, &drop_count, &keep_count));
+ CHECK_RESULT(wabt_typechecker_end_function(&ctx->typechecker));
+ CHECK_RESULT(emit_drop_keep(ctx, drop_count, keep_count));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_RETURN));
pop_label(ctx);
ctx->current_func = NULL;
- ctx->type_stack.size = 0;
return WABT_OK;
}
@@ -1295,7 +1073,6 @@ static WabtResult on_local_decl(uint32_t decl_index,
WabtType type,
void* user_data) {
Context* ctx = user_data;
- LOGF("%3" PRIzd ": alloca\n", ctx->type_stack.size);
WabtInterpreterFunc* func = ctx->current_func;
func->defined.local_count += count;
@@ -1303,17 +1080,12 @@ static WabtResult on_local_decl(uint32_t decl_index,
for (i = 0; i < count; ++i) {
wabt_append_type_value(ctx->allocator, &func->defined.param_and_local_types,
&type);
- push_type(ctx, type);
}
if (decl_index == func->defined.local_decl_count - 1) {
/* last local declaration, allocate space for all locals. */
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_ALLOCA));
CHECK_RESULT(emit_i32(ctx, func->defined.local_count));
- /* fixup the function label's type_stack_limit to include these values. */
- Label* label = top_label(ctx);
- assert(label->label_type == LABEL_TYPE_FUNC);
- label->type_stack_limit += func->defined.local_count;
}
return WABT_OK;
}
@@ -1340,14 +1112,14 @@ static WabtResult check_align(Context* ctx,
static WabtResult on_unary_expr(WabtOpcode opcode, void* user_data) {
Context* ctx = user_data;
- CHECK_RESULT(check_opcode1(ctx, opcode));
+ CHECK_RESULT(wabt_typechecker_on_unary(&ctx->typechecker, opcode));
CHECK_RESULT(emit_opcode(ctx, opcode));
return WABT_OK;
}
static WabtResult on_binary_expr(WabtOpcode opcode, void* user_data) {
Context* ctx = user_data;
- CHECK_RESULT(check_opcode2(ctx, opcode));
+ CHECK_RESULT(wabt_typechecker_on_binary(&ctx->typechecker, opcode));
CHECK_RESULT(emit_opcode(ctx, opcode));
return WABT_OK;
}
@@ -1359,8 +1131,8 @@ static WabtResult on_block_expr(uint32_t num_types,
WabtTypeVector sig;
sig.size = num_types;
sig.data = sig_types;
- push_label(ctx, LABEL_TYPE_BLOCK, &sig, WABT_INVALID_OFFSET,
- WABT_INVALID_OFFSET);
+ CHECK_RESULT(wabt_typechecker_on_block(&ctx->typechecker, &sig));
+ push_label(ctx, WABT_INVALID_OFFSET, WABT_INVALID_OFFSET);
return WABT_OK;
}
@@ -1371,8 +1143,8 @@ static WabtResult on_loop_expr(uint32_t num_types,
WabtTypeVector sig;
sig.size = num_types;
sig.data = sig_types;
- push_label(ctx, LABEL_TYPE_LOOP, &sig, get_istream_offset(ctx),
- WABT_INVALID_OFFSET);
+ CHECK_RESULT(wabt_typechecker_on_loop(&ctx->typechecker, &sig));
+ push_label(ctx, get_istream_offset(ctx), WABT_INVALID_OFFSET);
return WABT_OK;
}
@@ -1380,106 +1152,63 @@ static WabtResult on_if_expr(uint32_t num_types,
WabtType* sig_types,
void* user_data) {
Context* ctx = user_data;
- CHECK_RESULT(check_type_stack_limit(ctx, 1, "if"));
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "if"));
- CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR_UNLESS));
- uint32_t fixup_offset = get_istream_offset(ctx);
- CHECK_RESULT(emit_i32(ctx, WABT_INVALID_OFFSET));
-
WabtTypeVector sig;
sig.size = num_types;
sig.data = sig_types;
- push_label(ctx, LABEL_TYPE_IF, &sig, WABT_INVALID_OFFSET, fixup_offset);
+ CHECK_RESULT(wabt_typechecker_on_if(&ctx->typechecker, &sig));
+ CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR_UNLESS));
+ uint32_t fixup_offset = get_istream_offset(ctx);
+ CHECK_RESULT(emit_i32(ctx, WABT_INVALID_OFFSET));
+ push_label(ctx, WABT_INVALID_OFFSET, fixup_offset);
return WABT_OK;
}
static WabtResult on_else_expr(void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_else(&ctx->typechecker));
Label* label = top_label(ctx);
- if (!label || label->label_type != LABEL_TYPE_IF) {
- print_error(ctx, "unexpected else operator");
- return WABT_ERROR;
- }
-
- CHECK_RESULT(check_n_types(ctx, &label->sig, "if true branch"));
-
- label->label_type = LABEL_TYPE_ELSE;
uint32_t fixup_cond_offset = label->fixup_offset;
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR));
label->fixup_offset = get_istream_offset(ctx);
CHECK_RESULT(emit_i32(ctx, WABT_INVALID_OFFSET));
CHECK_RESULT(emit_i32_at(ctx, fixup_cond_offset, get_istream_offset(ctx)));
- /* reset the type stack for the other branch arm */
- ctx->type_stack.size = label->type_stack_limit;
return WABT_OK;
}
static WabtResult on_end_expr(void* user_data) {
Context* ctx = user_data;
- Label* label = top_label(ctx);
- if (!label) {
- print_error(ctx, "unexpected end operator");
- return WABT_ERROR;
- }
-
- const char* desc = NULL;
- switch (label->label_type) {
- case LABEL_TYPE_IF:
- case LABEL_TYPE_ELSE:
- desc = (label->label_type == LABEL_TYPE_IF) ? "if true branch"
- : "if false branch";
- CHECK_RESULT(
- emit_i32_at(ctx, label->fixup_offset, get_istream_offset(ctx)));
- break;
-
- case LABEL_TYPE_BLOCK:
- desc = "block";
- break;
-
- case LABEL_TYPE_LOOP:
- desc = "loop";
- break;
-
- case LABEL_TYPE_FUNC:
- print_error(ctx, "unexpected end operator");
- return WABT_ERROR;
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(wabt_typechecker_get_label(&ctx->typechecker, 0, &label));
+ WabtLabelType label_type = label->label_type;
+ CHECK_RESULT(wabt_typechecker_on_end(&ctx->typechecker));
+ if (label_type == WABT_LABEL_TYPE_IF || label_type == WABT_LABEL_TYPE_ELSE) {
+ CHECK_RESULT(emit_i32_at(ctx, top_label(ctx)->fixup_offset,
+ get_istream_offset(ctx)));
}
-
- CHECK_RESULT(check_n_types(ctx, &label->sig, desc));
- CHECK_RESULT(check_type_stack_limit_exact(ctx, label->sig.size, desc));
- fixup_top_label(ctx, get_istream_offset(ctx));
- reset_type_stack_to_limit(ctx);
- push_types(ctx, &label->sig);
+ fixup_top_label(ctx);
pop_label(ctx);
return WABT_OK;
}
static WabtResult on_br_expr(uint32_t depth, void* user_data) {
Context* ctx = user_data;
- CHECK_DEPTH(ctx, depth);
- depth = translate_depth(ctx, depth);
- Label* label = get_label(ctx, depth);
- if (label->label_type != LABEL_TYPE_LOOP)
- CHECK_RESULT(check_n_types(ctx, &label->sig, "br"));
- CHECK_RESULT(emit_br(ctx, depth));
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ uint32_t drop_count, keep_count;
+ CHECK_RESULT(get_br_drop_keep_count(ctx, depth, &drop_count, &keep_count));
+ CHECK_RESULT(wabt_typechecker_on_br(&ctx->typechecker, depth));
+ CHECK_RESULT(emit_br(ctx, depth, drop_count, keep_count));
return WABT_OK;
}
static WabtResult on_br_if_expr(uint32_t depth, void* user_data) {
Context* ctx = user_data;
- CHECK_DEPTH(ctx, depth);
- depth = translate_depth(ctx, depth);
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "br_if"));
- Label* label = get_label(ctx, depth);
- if (label->label_type != LABEL_TYPE_LOOP)
- CHECK_RESULT(check_n_types(ctx, &label->sig, "br_if"));
+ uint32_t drop_count, keep_count;
+ CHECK_RESULT(wabt_typechecker_on_br_if(&ctx->typechecker, depth));
+ CHECK_RESULT(get_br_drop_keep_count(ctx, depth, &drop_count, &keep_count));
/* flip the br_if so if <cond> is true it can drop values from the stack */
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR_UNLESS));
uint32_t fixup_br_offset = get_istream_offset(ctx);
CHECK_RESULT(emit_i32(ctx, WABT_INVALID_OFFSET));
- CHECK_RESULT(emit_br(ctx, depth));
+ CHECK_RESULT(emit_br(ctx, depth, drop_count, keep_count));
CHECK_RESULT(emit_i32_at(ctx, fixup_br_offset, get_istream_offset(ctx)));
return WABT_OK;
}
@@ -1489,7 +1218,7 @@ static WabtResult on_br_table_expr(WabtBinaryReaderContext* context,
uint32_t* target_depths,
uint32_t default_target_depth) {
Context* ctx = context->user_data;
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "br_table"));
+ CHECK_RESULT(wabt_typechecker_begin_br_table(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_BR_TABLE));
CHECK_RESULT(emit_i32(ctx, num_targets));
uint32_t fixup_table_offset = get_istream_offset(ctx);
@@ -1503,15 +1232,11 @@ static WabtResult on_br_table_expr(WabtBinaryReaderContext* context,
uint32_t i;
for (i = 0; i <= num_targets; ++i) {
uint32_t depth = i != num_targets ? target_depths[i] : default_target_depth;
- CHECK_DEPTH(ctx, depth);
- depth = translate_depth(ctx, depth);
- Label* label = get_label(ctx, depth);
- CHECK_RESULT(check_n_types(ctx, &label->sig, "br_table"));
+ CHECK_RESULT(wabt_typechecker_on_br_table_target(&ctx->typechecker, depth));
CHECK_RESULT(emit_br_table_offset(ctx, depth));
}
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ CHECK_RESULT(wabt_typechecker_end_br_table(&ctx->typechecker));
return WABT_OK;
}
@@ -1520,13 +1245,8 @@ static WabtResult on_call_expr(uint32_t func_index, void* user_data) {
WabtInterpreterFunc* func = get_func_by_module_index(ctx, func_index);
WabtInterpreterFuncSignature* sig =
get_signature_by_env_index(ctx, func->sig_index);
- CHECK_RESULT(check_type_stack_limit(ctx, sig->param_types.size, "call"));
-
- uint32_t i;
- for (i = sig->param_types.size; i > 0; --i) {
- WabtType arg = pop_type(ctx);
- CHECK_RESULT(check_type(ctx, sig->param_types.data[i - 1], arg, "call"));
- }
+ CHECK_RESULT(wabt_typechecker_on_call(&ctx->typechecker, &sig->param_types,
+ &sig->result_types));
if (func->is_host) {
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_CALL_HOST));
@@ -1535,7 +1255,6 @@ static WabtResult on_call_expr(uint32_t func_index, void* user_data) {
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_CALL));
CHECK_RESULT(emit_func_offset(ctx, func, func_index));
}
- push_types(ctx, &sig->result_types);
return WABT_OK;
}
@@ -1548,61 +1267,51 @@ static WabtResult on_call_indirect_expr(uint32_t sig_index, void* user_data) {
}
WabtInterpreterFuncSignature* sig =
get_signature_by_module_index(ctx, sig_index);
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "call_indirect"));
- CHECK_RESULT(
- check_type_stack_limit(ctx, sig->param_types.size, "call_indirect"));
-
- uint32_t i;
- for (i = sig->param_types.size; i > 0; --i) {
- WabtType arg = pop_type(ctx);
- CHECK_RESULT(
- check_type(ctx, sig->param_types.data[i - 1], arg, "call_indirect"));
- }
+ CHECK_RESULT(wabt_typechecker_on_call_indirect(
+ &ctx->typechecker, &sig->param_types, &sig->result_types));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_CALL_INDIRECT));
CHECK_RESULT(emit_i32(ctx, ctx->module->table_index));
CHECK_RESULT(emit_i32(ctx, translate_sig_index_to_env(ctx, sig_index)));
- push_types(ctx, &sig->result_types);
return WABT_OK;
}
static WabtResult on_drop_expr(void* user_data) {
Context* ctx = user_data;
- CHECK_RESULT(check_type_stack_limit(ctx, 1, "drop"));
+ CHECK_RESULT(wabt_typechecker_on_drop(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_DROP));
- pop_type(ctx);
return WABT_OK;
}
static WabtResult on_i32_const_expr(uint32_t value, void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_const(&ctx->typechecker, WABT_TYPE_I32));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_I32_CONST));
CHECK_RESULT(emit_i32(ctx, value));
- push_type(ctx, WABT_TYPE_I32);
return WABT_OK;
}
static WabtResult on_i64_const_expr(uint64_t value, void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_const(&ctx->typechecker, WABT_TYPE_I64));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_I64_CONST));
CHECK_RESULT(emit_i64(ctx, value));
- push_type(ctx, WABT_TYPE_I64);
return WABT_OK;
}
static WabtResult on_f32_const_expr(uint32_t value_bits, void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_const(&ctx->typechecker, WABT_TYPE_F32));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_F32_CONST));
CHECK_RESULT(emit_i32(ctx, value_bits));
- push_type(ctx, WABT_TYPE_F32);
return WABT_OK;
}
static WabtResult on_f64_const_expr(uint64_t value_bits, void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_const(&ctx->typechecker, WABT_TYPE_F64));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_F64_CONST));
CHECK_RESULT(emit_i64(ctx, value_bits));
- push_type(ctx, WABT_TYPE_F64);
return WABT_OK;
}
@@ -1610,9 +1319,9 @@ static WabtResult on_get_global_expr(uint32_t global_index, void* user_data) {
Context* ctx = user_data;
CHECK_GLOBAL(ctx, global_index);
WabtType type = get_global_type_by_module_index(ctx, global_index);
+ CHECK_RESULT(wabt_typechecker_on_get_global(&ctx->typechecker, type));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_GET_GLOBAL));
CHECK_RESULT(emit_i32(ctx, translate_global_index_to_env(ctx, global_index)));
- push_type(ctx, type);
return WABT_OK;
}
@@ -1625,20 +1334,29 @@ static WabtResult on_set_global_expr(uint32_t global_index, void* user_data) {
global_index);
return WABT_ERROR;
}
- CHECK_RESULT(
- pop_and_check_1_type(ctx, global->typed_value.type, "set_global"));
+ CHECK_RESULT(wabt_typechecker_on_set_global(&ctx->typechecker,
+ global->typed_value.type));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_SET_GLOBAL));
CHECK_RESULT(emit_i32(ctx, translate_global_index_to_env(ctx, global_index)));
return WABT_OK;
}
+static uint32_t translate_local_index(Context* ctx, uint32_t local_index) {
+ return ctx->typechecker.type_stack.size +
+ ctx->current_func->defined.param_and_local_types.size - local_index;
+}
+
static WabtResult on_get_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
CHECK_LOCAL(ctx, local_index);
WabtType type = get_local_type_by_index(ctx->current_func, local_index);
+ /* Get the translated index before calling wabt_typechecker_on_get_local
+ * because it will update the type stack size. We need the index to be
+ * relative to the old stack size. */
+ uint32_t translated_local_index = translate_local_index(ctx, local_index);
+ CHECK_RESULT(wabt_typechecker_on_get_local(&ctx->typechecker, type));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_GET_LOCAL));
- CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
- push_type(ctx, type);
+ CHECK_RESULT(emit_i32(ctx, translated_local_index));
return WABT_OK;
}
@@ -1646,7 +1364,7 @@ static WabtResult on_set_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
CHECK_LOCAL(ctx, local_index);
WabtType type = get_local_type_by_index(ctx->current_func, local_index);
- CHECK_RESULT(pop_and_check_1_type(ctx, type, "set_local"));
+ CHECK_RESULT(wabt_typechecker_on_set_local(&ctx->typechecker, type));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_SET_LOCAL));
CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
return WABT_OK;
@@ -1656,9 +1374,7 @@ static WabtResult on_tee_local_expr(uint32_t local_index, void* user_data) {
Context* ctx = user_data;
CHECK_LOCAL(ctx, local_index);
WabtType type = get_local_type_by_index(ctx->current_func, local_index);
- CHECK_RESULT(check_type_stack_limit(ctx, 1, "tee_local"));
- WabtType value = top_type(ctx);
- CHECK_RESULT(check_type(ctx, type, value, "tee_local"));
+ CHECK_RESULT(wabt_typechecker_on_tee_local(&ctx->typechecker, type));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_TEE_LOCAL));
CHECK_RESULT(emit_i32(ctx, translate_local_index(ctx, local_index)));
return WABT_OK;
@@ -1667,10 +1383,9 @@ static WabtResult on_tee_local_expr(uint32_t local_index, void* user_data) {
static WabtResult on_grow_memory_expr(void* user_data) {
Context* ctx = user_data;
CHECK_RESULT(check_has_memory(ctx, WABT_OPCODE_GROW_MEMORY));
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "grow_memory"));
+ CHECK_RESULT(wabt_typechecker_on_grow_memory(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_GROW_MEMORY));
CHECK_RESULT(emit_i32(ctx, ctx->module->memory_index));
- push_type(ctx, WABT_TYPE_I32);
return WABT_OK;
}
@@ -1682,7 +1397,7 @@ static WabtResult on_load_expr(WabtOpcode opcode,
CHECK_RESULT(check_has_memory(ctx, opcode));
CHECK_RESULT(
check_align(ctx, alignment_log2, wabt_get_opcode_memory_size(opcode)));
- CHECK_RESULT(check_opcode1(ctx, opcode));
+ CHECK_RESULT(wabt_typechecker_on_load(&ctx->typechecker, opcode));
CHECK_RESULT(emit_opcode(ctx, opcode));
CHECK_RESULT(emit_i32(ctx, ctx->module->memory_index));
CHECK_RESULT(emit_i32(ctx, offset));
@@ -1697,7 +1412,7 @@ static WabtResult on_store_expr(WabtOpcode opcode,
CHECK_RESULT(check_has_memory(ctx, opcode));
CHECK_RESULT(
check_align(ctx, alignment_log2, wabt_get_opcode_memory_size(opcode)));
- CHECK_RESULT(check_opcode2(ctx, opcode));
+ CHECK_RESULT(wabt_typechecker_on_store(&ctx->typechecker, opcode));
CHECK_RESULT(emit_opcode(ctx, opcode));
CHECK_RESULT(emit_i32(ctx, ctx->module->memory_index));
CHECK_RESULT(emit_i32(ctx, offset));
@@ -1707,9 +1422,9 @@ static WabtResult on_store_expr(WabtOpcode opcode,
static WabtResult on_current_memory_expr(void* user_data) {
Context* ctx = user_data;
CHECK_RESULT(check_has_memory(ctx, WABT_OPCODE_CURRENT_MEMORY));
+ CHECK_RESULT(wabt_typechecker_on_current_memory(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_CURRENT_MEMORY));
CHECK_RESULT(emit_i32(ctx, ctx->module->memory_index));
- push_type(ctx, WABT_TYPE_I32);
return WABT_OK;
}
@@ -1719,33 +1434,25 @@ static WabtResult on_nop_expr(void* user_data) {
static WabtResult on_return_expr(void* user_data) {
Context* ctx = user_data;
- WabtInterpreterFuncSignature* sig =
- get_signature_by_env_index(ctx, ctx->current_func->sig_index);
- CHECK_RESULT(check_n_types(ctx, &sig->result_types, "return"));
- CHECK_RESULT(drop_types_for_return(ctx, sig->result_types.size));
+ uint32_t drop_count, keep_count;
+ CHECK_RESULT(get_return_drop_keep_count(ctx, &drop_count, &keep_count));
+ CHECK_RESULT(wabt_typechecker_on_return(&ctx->typechecker));
+ CHECK_RESULT(emit_drop_keep(ctx, drop_count, keep_count));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_RETURN));
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
return WABT_OK;
}
static WabtResult on_select_expr(void* user_data) {
Context* ctx = user_data;
- CHECK_RESULT(pop_and_check_1_type(ctx, WABT_TYPE_I32, "select"));
- CHECK_RESULT(check_type_stack_limit(ctx, 2, "select"));
- WabtType right = pop_type(ctx);
- WabtType left = pop_type(ctx);
- CHECK_RESULT(check_type(ctx, left, right, "select"));
+ CHECK_RESULT(wabt_typechecker_on_select(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_SELECT));
- push_type(ctx, left);
return WABT_OK;
}
static WabtResult on_unreachable_expr(void* user_data) {
Context* ctx = user_data;
+ CHECK_RESULT(wabt_typechecker_on_unreachable(&ctx->typechecker));
CHECK_RESULT(emit_opcode(ctx, WABT_OPCODE_UNREACHABLE));
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
return WABT_OK;
}
@@ -1844,8 +1551,7 @@ static WabtBinaryReader s_binary_reader_segments = {
};
static void destroy_context(Context* ctx) {
- wabt_destroy_type_vector(ctx->allocator, &ctx->type_stack);
- WABT_DESTROY_VECTOR_AND_ELEMENTS(ctx->allocator, ctx->label_stack, label);
+ wabt_destroy_label_vector(ctx->allocator, &ctx->label_stack);
WABT_DESTROY_VECTOR_AND_ELEMENTS(ctx->allocator, ctx->depth_fixups,
uint32_vector);
WABT_DESTROY_VECTOR_AND_ELEMENTS(ctx->allocator, ctx->func_fixups,
@@ -1853,6 +1559,7 @@ static void destroy_context(Context* ctx) {
wabt_destroy_uint32_vector(ctx->allocator, &ctx->sig_index_mapping);
wabt_destroy_uint32_vector(ctx->allocator, &ctx->func_index_mapping);
wabt_destroy_uint32_vector(ctx->allocator, &ctx->global_index_mapping);
+ wabt_destroy_typechecker(&ctx->typechecker);
}
WabtResult wabt_read_binary_interpreter(WabtAllocator* allocator,
@@ -1889,6 +1596,12 @@ WabtResult wabt_read_binary_interpreter(WabtAllocator* allocator,
CHECK_RESULT(
wabt_init_mem_writer_existing(&ctx.istream_writer, &env->istream));
+ WabtTypeCheckerErrorHandler tc_error_handler;
+ tc_error_handler.on_error = on_typechecker_error;
+ tc_error_handler.user_data = &ctx;
+ ctx.typechecker.allocator = allocator;
+ ctx.typechecker.error_handler = &tc_error_handler;
+
reader = s_binary_reader;
reader.user_data = &ctx;
diff --git a/src/common.h b/src/common.h
index 2f66cd44..e11841e7 100644
--- a/src/common.h
+++ b/src/common.h
@@ -81,6 +81,15 @@ typedef enum WabtResult {
#define WABT_SUCCEEDED(x) ((x) == WABT_OK)
#define WABT_FAILED(x) ((x) == WABT_ERROR)
+typedef enum WabtLabelType {
+ WABT_LABEL_TYPE_FUNC,
+ WABT_LABEL_TYPE_BLOCK,
+ WABT_LABEL_TYPE_LOOP,
+ WABT_LABEL_TYPE_IF,
+ WABT_LABEL_TYPE_ELSE,
+ WABT_NUM_LABEL_TYPES,
+} WabtLabelType;
+
typedef struct WabtStringSlice {
const char* start;
size_t length;
diff --git a/src/type-checker.c b/src/type-checker.c
new file mode 100644
index 00000000..5ac7ed31
--- /dev/null
+++ b/src/type-checker.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#include "type-checker.h"
+
+#define CHECK_RESULT(expr) \
+ do { \
+ if (WABT_FAILED(expr)) \
+ return WABT_ERROR; \
+ } while (0)
+
+#define COMBINE_RESULT(result_var, result) \
+ do { \
+ (result_var) |= (result); \
+ } while (0)
+
+static void WABT_PRINTF_FORMAT(2, 3)
+ print_error(WabtTypeChecker* tc, const char* fmt, ...) {
+ if (tc->error_handler->on_error) {
+ WABT_SNPRINTF_ALLOCA(buffer, length, fmt);
+ tc->error_handler->on_error(buffer, tc->error_handler->user_data);
+ }
+}
+
+WabtResult wabt_typechecker_get_label(WabtTypeChecker* tc,
+ size_t depth,
+ WabtTypeCheckerLabel** out_label) {
+ if (depth >= tc->label_stack.size) {
+ assert(tc->label_stack.size > 0);
+ print_error(tc, "invalid depth: %" PRIzd " (max %" PRIzd ")",
+ depth, tc->label_stack.size - 1);
+ *out_label = NULL;
+ return WABT_ERROR;
+ }
+ *out_label = &tc->label_stack.data[tc->label_stack.size - depth - 1];
+ return WABT_OK;
+}
+
+static WabtResult top_label(WabtTypeChecker* tc,
+ WabtTypeCheckerLabel** out_label) {
+ return wabt_typechecker_get_label(tc, 0, out_label);
+}
+
+WabtBool wabt_typechecker_is_unreachable(WabtTypeChecker* tc) {
+ WabtTypeCheckerLabel* label;
+ if (WABT_FAILED(top_label(tc, &label)))
+ return WABT_TRUE;
+ return label->unreachable;
+}
+
+static void reset_type_stack_to_label(WabtTypeChecker* tc,
+ WabtTypeCheckerLabel* label) {
+ tc->type_stack.size = label->type_stack_limit;
+}
+
+static WabtResult set_unreachable(WabtTypeChecker* tc) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ label->unreachable = WABT_TRUE;
+ reset_type_stack_to_label(tc, label);
+ return WABT_OK;
+}
+
+static void push_label(WabtTypeChecker* tc,
+ WabtLabelType label_type,
+ const WabtTypeVector* sig) {
+ WabtTypeCheckerLabel* label =
+ wabt_append_type_checker_label(tc->allocator, &tc->label_stack);
+ label->label_type = label_type;
+ wabt_extend_types(tc->allocator, &label->sig, sig);
+ label->type_stack_limit = tc->type_stack.size;
+ label->unreachable = WABT_FALSE;
+}
+
+static void wabt_destroy_type_checker_label(WabtAllocator* allocator,
+ WabtTypeCheckerLabel* label) {
+ wabt_destroy_type_vector(allocator, &label->sig);
+}
+
+static WabtResult pop_label(WabtTypeChecker* tc) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ wabt_destroy_type_checker_label(tc->allocator, label);
+ tc->label_stack.size--;
+ return WABT_OK;
+}
+
+static WabtResult check_label_type(WabtTypeCheckerLabel* label,
+ WabtLabelType label_type) {
+ return label->label_type == label_type ? WABT_OK : WABT_ERROR;
+}
+
+static WabtResult peek_type(WabtTypeChecker* tc,
+ uint32_t depth,
+ WabtType* out_type) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+
+ if (label->type_stack_limit + depth >= tc->type_stack.size) {
+ *out_type = WABT_TYPE_ANY;
+ return label->unreachable ? WABT_OK : WABT_ERROR;
+ }
+ *out_type = tc->type_stack.data[tc->type_stack.size - depth - 1];
+ return WABT_OK;
+}
+
+static WabtResult top_type(WabtTypeChecker* tc, WabtType* out_type) {
+ return peek_type(tc, 0, out_type);
+}
+
+static WabtResult pop_type(WabtTypeChecker* tc, WabtType* out_type) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ WabtResult result = top_type(tc, out_type);
+ if (tc->type_stack.size > label->type_stack_limit)
+ tc->type_stack.size--;
+ return result;
+}
+
+static WabtResult drop_types(WabtTypeChecker* tc, size_t drop_count) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ if (label->type_stack_limit + drop_count > tc->type_stack.size) {
+ if (label->unreachable) {
+ reset_type_stack_to_label(tc, label);
+ return WABT_OK;
+ }
+ return WABT_ERROR;
+ }
+ tc->type_stack.size -= drop_count;
+ return WABT_OK;
+}
+
+static void push_type(WabtTypeChecker* tc, WabtType type) {
+ if (type != WABT_TYPE_VOID)
+ wabt_append_type_value(tc->allocator, &tc->type_stack, &type);
+}
+
+static void push_types(WabtTypeChecker* tc, const WabtTypeVector* types) {
+ size_t i;
+ for (i = 0; i < types->size; ++i)
+ push_type(tc, types->data[i]);
+}
+
+static WabtResult check_type_stack_limit(WabtTypeChecker* tc,
+ size_t expected,
+ const char* desc) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ size_t avail = tc->type_stack.size - label->type_stack_limit;
+ if (!label->unreachable && expected > avail) {
+ print_error(tc, "type stack size too small at %s. got %" PRIzd
+ ", expected at least %" PRIzd,
+ desc, avail, expected);
+ return WABT_ERROR;
+ }
+ return WABT_OK;
+}
+
+static WabtResult check_type_stack_end(WabtTypeChecker* tc, const char* desc) {
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ if (tc->type_stack.size != label->type_stack_limit) {
+ print_error(tc, "type stack at end of %s is %" PRIzd ", expected %" PRIzd,
+ desc, tc->type_stack.size, label->type_stack_limit);
+ return WABT_ERROR;
+ }
+ return WABT_OK;
+}
+
+static WabtResult check_type(WabtTypeChecker* tc,
+ WabtType actual,
+ WabtType expected,
+ const char* desc) {
+ if (expected != actual && expected != WABT_TYPE_ANY &&
+ actual != WABT_TYPE_ANY) {
+ print_error(tc, "type mismatch in %s, expected %s but got %s.", desc,
+ wabt_get_type_name(expected), wabt_get_type_name(actual));
+ return WABT_ERROR;
+ }
+ return WABT_OK;
+}
+
+static WabtResult check_signature(WabtTypeChecker* tc,
+ const WabtTypeVector* sig,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ size_t i;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, sig->size, desc));
+ for (i = 0; i < sig->size; ++i) {
+ WabtType actual = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, peek_type(tc, sig->size - i - 1, &actual));
+ COMBINE_RESULT(result, check_type(tc, actual, sig->data[i], desc));
+ }
+ return result;
+}
+
+static WabtResult pop_and_check_signature(WabtTypeChecker* tc,
+ const WabtTypeVector* sig,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ COMBINE_RESULT(result, check_signature(tc, sig, desc));
+ COMBINE_RESULT(result, drop_types(tc, sig->size));
+ return result;
+}
+
+static WabtResult pop_and_check_call(WabtTypeChecker* tc,
+ const WabtTypeVector* param_types,
+ const WabtTypeVector* result_types,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ size_t i;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, param_types->size, desc));
+ for (i = 0; i < param_types->size; ++i) {
+ WabtType actual = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, peek_type(tc, param_types->size - i - 1, &actual));
+ COMBINE_RESULT(result, check_type(tc, actual, param_types->data[i], desc));
+ }
+ COMBINE_RESULT(result, drop_types(tc, param_types->size));
+ push_types(tc, result_types);
+ return result;
+}
+
+static WabtResult pop_and_check_1_type(WabtTypeChecker* tc,
+ WabtType expected,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ WabtType actual = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, 1, desc));
+ COMBINE_RESULT(result, pop_type(tc, &actual));
+ COMBINE_RESULT(result, check_type(tc, actual, expected, desc));
+ return result;
+}
+
+static WabtResult pop_and_check_2_types(WabtTypeChecker* tc,
+ WabtType expected1,
+ WabtType expected2,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ WabtType actual1 = WABT_TYPE_ANY;
+ WabtType actual2 = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, 2, desc));
+ COMBINE_RESULT(result, pop_type(tc, &actual2));
+ COMBINE_RESULT(result, pop_type(tc, &actual1));
+ COMBINE_RESULT(result, check_type(tc, actual1, expected1, desc));
+ COMBINE_RESULT(result, check_type(tc, actual2, expected2, desc));
+ return result;
+}
+
+static WabtResult pop_and_check_2_types_are_equal(WabtTypeChecker* tc,
+ WabtType* out_type,
+ const char* desc) {
+ WabtResult result = WABT_OK;
+ WabtType right = WABT_TYPE_ANY;
+ WabtType left = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, 2, desc));
+ COMBINE_RESULT(result, pop_type(tc, &right));
+ COMBINE_RESULT(result, pop_type(tc, &left));
+ COMBINE_RESULT(result, check_type(tc, left, right, desc));
+ *out_type = right;
+ return result;
+}
+
+static WabtResult check_opcode1(WabtTypeChecker* tc, WabtOpcode opcode) {
+ WabtResult result = pop_and_check_1_type(
+ tc, wabt_get_opcode_param_type_1(opcode), wabt_get_opcode_name(opcode));
+ push_type(tc, wabt_get_opcode_result_type(opcode));
+ return result;
+}
+
+static WabtResult check_opcode2(WabtTypeChecker* tc, WabtOpcode opcode) {
+ WabtResult result = pop_and_check_2_types(
+ tc, wabt_get_opcode_param_type_1(opcode),
+ wabt_get_opcode_param_type_2(opcode), wabt_get_opcode_name(opcode));
+ push_type(tc, wabt_get_opcode_result_type(opcode));
+ return result;
+}
+
+void wabt_destroy_typechecker(WabtTypeChecker* tc) {
+ wabt_destroy_type_vector(tc->allocator, &tc->type_stack);
+ WABT_DESTROY_VECTOR_AND_ELEMENTS(tc->allocator, tc->label_stack,
+ type_checker_label);
+}
+
+WabtResult wabt_typechecker_begin_function(WabtTypeChecker* tc,
+ const WabtTypeVector* sig) {
+ tc->type_stack.size = 0;
+ tc->label_stack.size = 0;
+ push_label(tc, WABT_LABEL_TYPE_FUNC, sig);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_binary(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode2(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_block(WabtTypeChecker* tc,
+ const WabtTypeVector* sig) {
+ push_label(tc, WABT_LABEL_TYPE_BLOCK, sig);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_br(WabtTypeChecker* tc, size_t depth) {
+ WabtResult result = WABT_OK;
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(wabt_typechecker_get_label(tc, depth, &label));
+ if (label->label_type != WABT_LABEL_TYPE_LOOP)
+ COMBINE_RESULT(result, check_signature(tc, &label->sig, "br"));
+ CHECK_RESULT(set_unreachable(tc));
+ return result;
+}
+
+WabtResult wabt_typechecker_on_br_if(WabtTypeChecker* tc, size_t depth) {
+ WabtResult result = WABT_OK;
+ COMBINE_RESULT(result, pop_and_check_1_type(tc, WABT_TYPE_I32, "br_if"));
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(wabt_typechecker_get_label(tc, depth, &label));
+ if (label->label_type != WABT_LABEL_TYPE_LOOP)
+ COMBINE_RESULT(result, check_signature(tc, &label->sig, "br_if"));
+ return result;
+}
+
+WabtResult wabt_typechecker_begin_br_table(WabtTypeChecker* tc) {
+ return pop_and_check_1_type(tc, WABT_TYPE_I32, "br_table");
+}
+
+WabtResult wabt_typechecker_on_br_table_target(WabtTypeChecker* tc,
+ size_t depth) {
+ WabtResult result = WABT_OK;
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(wabt_typechecker_get_label(tc, depth, &label));
+ if (label->label_type != WABT_LABEL_TYPE_LOOP)
+ COMBINE_RESULT(result, check_signature(tc, &label->sig, "br_table"));
+ return result;
+}
+
+WabtResult wabt_typechecker_end_br_table(WabtTypeChecker* tc) {
+ return set_unreachable(tc);
+}
+
+WabtResult wabt_typechecker_on_call(WabtTypeChecker* tc,
+ const WabtTypeVector* param_types,
+ const WabtTypeVector* result_types) {
+ return pop_and_check_call(tc, param_types, result_types, "call");
+}
+
+WabtResult wabt_typechecker_on_call_indirect(
+ WabtTypeChecker* tc,
+ const WabtTypeVector* param_types,
+ const WabtTypeVector* result_types) {
+ WabtResult result = WABT_OK;
+ COMBINE_RESULT(result,
+ pop_and_check_1_type(tc, WABT_TYPE_I32, "call_indirect"));
+ COMBINE_RESULT(result, pop_and_check_call(tc, param_types, result_types,
+ "call_indirect"));
+ return result;
+}
+
+WabtResult wabt_typechecker_on_compare(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode2(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_const(WabtTypeChecker* tc, WabtType type) {
+ push_type(tc, type);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_convert(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode1(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_current_memory(WabtTypeChecker* tc) {
+ push_type(tc, WABT_TYPE_I32);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_drop(WabtTypeChecker* tc) {
+ WabtResult result = WABT_OK;
+ WabtType type = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, 1, "drop"));
+ COMBINE_RESULT(result, pop_type(tc, &type));
+ return result;
+}
+
+WabtResult wabt_typechecker_on_else(WabtTypeChecker* tc) {
+ WabtResult result = WABT_OK;
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ COMBINE_RESULT(result, check_label_type(label, WABT_LABEL_TYPE_IF));
+ COMBINE_RESULT(result,
+ pop_and_check_signature(tc, &label->sig, "if true branch"));
+ COMBINE_RESULT(result, check_type_stack_end(tc, "if true branch"));
+ reset_type_stack_to_label(tc, label);
+ label->label_type = WABT_LABEL_TYPE_ELSE;
+ label->unreachable = WABT_FALSE;
+ return result;
+}
+
+static WabtResult on_end(WabtTypeChecker* tc,
+ WabtTypeCheckerLabel* label,
+ const char* sig_desc,
+ const char* end_desc) {
+ WabtResult result = WABT_OK;
+ COMBINE_RESULT(result, pop_and_check_signature(tc, &label->sig, sig_desc));
+ COMBINE_RESULT(result, check_type_stack_end(tc, end_desc));
+ reset_type_stack_to_label(tc, label);
+ push_types(tc, &label->sig);
+ pop_label(tc);
+ return result;
+}
+
+WabtResult wabt_typechecker_on_end(WabtTypeChecker* tc) {
+ static const char* s_label_type_name[] = {"function", "block", "loop", "if",
+ "if false branch"};
+ WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_label_type_name) ==
+ WABT_NUM_LABEL_TYPES);
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ assert(label->label_type < WABT_NUM_LABEL_TYPES);
+ const char* desc = s_label_type_name[label->label_type];
+ return on_end(tc, label, desc, desc);
+}
+
+WabtResult wabt_typechecker_on_grow_memory(WabtTypeChecker* tc) {
+ return check_opcode1(tc, WABT_OPCODE_GROW_MEMORY);
+}
+
+WabtResult wabt_typechecker_on_if(WabtTypeChecker* tc,
+ const WabtTypeVector* sig) {
+ WabtResult result = pop_and_check_1_type(tc, WABT_TYPE_I32, "if");
+ push_label(tc, WABT_LABEL_TYPE_IF, sig);
+ return result;
+}
+
+WabtResult wabt_typechecker_on_get_global(WabtTypeChecker* tc, WabtType type) {
+ push_type(tc, type);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_get_local(WabtTypeChecker* tc, WabtType type) {
+ push_type(tc, type);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_load(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode1(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_loop(WabtTypeChecker* tc,
+ const WabtTypeVector* sig) {
+ push_label(tc, WABT_LABEL_TYPE_LOOP, sig);
+ return WABT_OK;
+}
+
+WabtResult wabt_typechecker_on_return(WabtTypeChecker* tc) {
+ WabtResult result = WABT_OK;
+ WabtTypeCheckerLabel* func_label;
+ CHECK_RESULT(
+ wabt_typechecker_get_label(tc, tc->label_stack.size - 1, &func_label));
+ COMBINE_RESULT(result,
+ pop_and_check_signature(tc, &func_label->sig, "return"));
+ CHECK_RESULT(set_unreachable(tc));
+ return result;
+}
+
+WabtResult wabt_typechecker_on_select(WabtTypeChecker* tc) {
+ WabtResult result = WABT_OK;
+ COMBINE_RESULT(result, pop_and_check_1_type(tc, WABT_TYPE_I32, "select"));
+ WabtType type = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, pop_and_check_2_types_are_equal(tc, &type, "select"));
+ push_type(tc, type);
+ return result;
+}
+
+WabtResult wabt_typechecker_on_set_global(WabtTypeChecker* tc, WabtType type) {
+ return pop_and_check_1_type(tc, type, "set_global");
+}
+
+WabtResult wabt_typechecker_on_set_local(WabtTypeChecker* tc, WabtType type) {
+ return pop_and_check_1_type(tc, type, "set_local");
+}
+
+WabtResult wabt_typechecker_on_store(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode2(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_tee_local(WabtTypeChecker* tc, WabtType type) {
+ WabtResult result = WABT_OK;
+ WabtType value = WABT_TYPE_ANY;
+ COMBINE_RESULT(result, check_type_stack_limit(tc, 1, "tee_local"));
+ COMBINE_RESULT(result, top_type(tc, &value));
+ COMBINE_RESULT(result, check_type(tc, value, type, "tee_local"));
+ return result;
+}
+
+WabtResult wabt_typechecker_on_unary(WabtTypeChecker* tc, WabtOpcode opcode) {
+ return check_opcode1(tc, opcode);
+}
+
+WabtResult wabt_typechecker_on_unreachable(WabtTypeChecker* tc) {
+ return set_unreachable(tc);
+}
+
+WabtResult wabt_typechecker_end_function(WabtTypeChecker* tc) {
+ WabtResult result = WABT_OK;
+ WabtTypeCheckerLabel* label;
+ CHECK_RESULT(top_label(tc, &label));
+ COMBINE_RESULT(result, check_label_type(label, WABT_LABEL_TYPE_FUNC));
+ COMBINE_RESULT(result, on_end(tc, label, "implicit return", "function"));
+ return result;
+}
diff --git a/src/type-checker.h b/src/type-checker.h
new file mode 100644
index 00000000..e4fd74e1
--- /dev/null
+++ b/src/type-checker.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#ifndef WABT_TYPE_CHECKER_H_
+#define WABT_TYPE_CHECKER_H_
+
+#include "common.h"
+#include "type-vector.h"
+#include "vector.h"
+
+struct WabtAllocator;
+
+typedef void (*WabtTypeCheckerErrorCallback)(const char* msg, void* user_data);
+
+typedef struct WabtTypeCheckerErrorHandler {
+ WabtTypeCheckerErrorCallback on_error;
+ void* user_data;
+} WabtTypeCheckerErrorHandler;
+
+typedef struct WabtTypeCheckerLabel {
+ WabtLabelType label_type;
+ WabtTypeVector sig;
+ size_t type_stack_limit;
+ WabtBool unreachable;
+} WabtTypeCheckerLabel;
+WABT_DEFINE_VECTOR(type_checker_label, WabtTypeCheckerLabel);
+
+typedef struct WabtTypeChecker {
+ WabtTypeCheckerErrorHandler* error_handler;
+ WabtAllocator* allocator;
+ WabtTypeVector type_stack;
+ WabtTypeCheckerLabelVector label_stack;
+} WabtTypeChecker;
+
+WABT_EXTERN_C_BEGIN
+
+void wabt_destroy_typechecker(WabtTypeChecker*);
+
+WabtBool wabt_typechecker_is_unreachable(WabtTypeChecker* tc);
+WabtResult wabt_typechecker_get_label(WabtTypeChecker* tc,
+ size_t depth,
+ WabtTypeCheckerLabel** out_label);
+
+WabtResult wabt_typechecker_begin_function(WabtTypeChecker*,
+ const WabtTypeVector* sig);
+WabtResult wabt_typechecker_on_binary(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_block(WabtTypeChecker*,
+ const WabtTypeVector* sig);
+WabtResult wabt_typechecker_on_br(WabtTypeChecker*, size_t depth);
+WabtResult wabt_typechecker_on_br_if(WabtTypeChecker*, size_t depth);
+WabtResult wabt_typechecker_begin_br_table(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_br_table_target(WabtTypeChecker*, size_t depth);
+WabtResult wabt_typechecker_end_br_table(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_call(WabtTypeChecker*,
+ const WabtTypeVector* param_types,
+ const WabtTypeVector* result_types);
+WabtResult wabt_typechecker_on_call_indirect(
+ WabtTypeChecker*,
+ const WabtTypeVector* param_types,
+ const WabtTypeVector* result_types);
+WabtResult wabt_typechecker_on_compare(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_const(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_convert(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_current_memory(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_drop(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_else(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_end(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_get_global(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_get_local(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_grow_memory(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_if(WabtTypeChecker*, const WabtTypeVector* sig);
+WabtResult wabt_typechecker_on_load(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_loop(WabtTypeChecker*,
+ const WabtTypeVector* sig);
+WabtResult wabt_typechecker_on_return(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_select(WabtTypeChecker*);
+WabtResult wabt_typechecker_on_set_global(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_set_local(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_store(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_tee_local(WabtTypeChecker*, WabtType);
+WabtResult wabt_typechecker_on_unary(WabtTypeChecker*, WabtOpcode);
+WabtResult wabt_typechecker_on_unreachable(WabtTypeChecker*);
+WabtResult wabt_typechecker_end_function(WabtTypeChecker*);
+
+WABT_EXTERN_C_END
+
+#endif /* WABT_TYPE_CHECKER_H_ */
diff --git a/src/validator.c b/src/validator.c
index 0f154548..0827ae02 100644
--- a/src/validator.c
+++ b/src/validator.c
@@ -27,21 +27,7 @@
#include "ast-parser-lexer-shared.h"
#include "binary-reader-ast.h"
#include "binary-reader.h"
-#include "resolve-names.h"
-
-typedef enum LabelType {
- LABEL_TYPE_FUNC,
- LABEL_TYPE_BLOCK,
- LABEL_TYPE_LOOP,
- LABEL_TYPE_IF,
-} LabelType;
-
-typedef struct LabelNode {
- LabelType label_type;
- const WabtTypeVector* sig;
- struct LabelNode* next;
- size_t type_stack_limit;
-} LabelNode;
+#include "type-checker.h"
typedef enum ActionResultKind {
ACTION_RESULT_KIND_ERROR,
@@ -68,9 +54,8 @@ typedef struct Context {
int current_memory_index;
int current_global_index;
int num_imported_globals;
- WabtTypeVector type_stack;
- LabelNode* top_label;
- int max_depth;
+ WabtTypeChecker typechecker;
+ const WabtLocation* expr_loc; /* Cached for access by on_typechecker_error */
WabtResult result;
} Context;
@@ -83,6 +68,11 @@ static void WABT_PRINTF_FORMAT(3, 4)
va_end(args);
}
+static void on_typechecker_error(const char* msg, void* user_data) {
+ Context* ctx = user_data;
+ print_error(ctx, ctx->expr_loc, "%s", msg);
+}
+
static WabtBool is_power_of_two(uint32_t x) {
return x && ((x & (x - 1)) == 0);
}
@@ -140,6 +130,13 @@ static WabtResult check_global_var(Context* ctx,
return WABT_OK;
}
+static WabtType get_global_var_type_or_any(Context* ctx, const WabtVar* var) {
+ const WabtGlobal* global;
+ if (WABT_SUCCEEDED(check_global_var(ctx, var, &global, NULL)))
+ return global->type;
+ return WABT_TYPE_ANY;
+}
+
static WabtResult check_func_type_var(Context* ctx,
const WabtVar* var,
const WabtFuncType** out_func_type) {
@@ -211,6 +208,12 @@ static WabtResult check_local_var(Context* ctx,
return WABT_ERROR;
}
+static WabtType get_local_var_type_or_any(Context* ctx, const WabtVar* var) {
+ WabtType type = WABT_TYPE_ANY;
+ check_local_var(ctx, var, &type);
+ return type;
+}
+
static void check_align(Context* ctx,
const WabtLocation* loc,
uint32_t alignment,
@@ -234,132 +237,12 @@ static void check_offset(Context* ctx,
}
}
-static LabelNode* find_label_by_var(LabelNode* top_label, const WabtVar* var) {
- assert(var->type == WABT_VAR_TYPE_INDEX);
- LabelNode* node = top_label;
- int i = 0;
- while (node && i != var->index) {
- node = node->next;
- i++;
- }
- return node;
-}
-
-static WabtResult check_label_var(Context* ctx,
- LabelNode* top_label,
- const WabtVar* var,
- LabelNode** out_node) {
- LabelNode* node = find_label_by_var(top_label, var);
- if (node) {
- if (out_node)
- *out_node = node;
- return WABT_OK;
- }
-
- print_error(ctx, &var->loc, "label variable out of range (max %d)",
- ctx->max_depth);
- return WABT_ERROR;
-}
-
-static void push_label(Context* ctx,
- const WabtLocation* loc,
- LabelNode* node,
- LabelType label_type,
- const WabtTypeVector* sig) {
- node->label_type = label_type;
- node->next = ctx->top_label;
- node->sig = sig;
- node->type_stack_limit = ctx->type_stack.size;
- ctx->top_label = node;
- ctx->max_depth++;
-}
-
-static void pop_label(Context* ctx) {
- ctx->max_depth--;
- ctx->top_label = ctx->top_label->next;
-}
-
-static size_t type_stack_limit(Context* ctx) {
- assert(ctx->top_label != NULL);
- return ctx->top_label->type_stack_limit;
-}
-
-static WabtResult check_type_stack_limit(Context* ctx,
- const WabtLocation* loc,
- size_t expected,
- const char* desc) {
- size_t limit = type_stack_limit(ctx);
- size_t avail = ctx->type_stack.size - limit;
- if (expected > avail) {
- print_error(ctx, loc, "type stack size too small at %s. got %" PRIzd
- ", expected at least %" PRIzd,
- desc, avail, expected);
- return WABT_ERROR;
- }
- return WABT_OK;
-}
-
-static WabtResult check_type_stack_limit_exact(Context* ctx,
- const WabtLocation* loc,
- size_t expected,
- const char* desc) {
- size_t limit = type_stack_limit(ctx);
- size_t avail = ctx->type_stack.size - limit;
- if (expected != avail) {
- print_error(ctx, loc,
- "type stack at end of %s is %" PRIzd ". expected %" PRIzd, desc,
- avail, expected);
- return WABT_ERROR;
- }
- return WABT_OK;
-}
-
-static void reset_type_stack_to_limit(Context* ctx) {
- ctx->type_stack.size = type_stack_limit(ctx);
-}
-
-static void push_type(Context* ctx, WabtType type) {
- if (type != WABT_TYPE_VOID)
- wabt_append_type_value(ctx->allocator, &ctx->type_stack, &type);
-}
-
-static void push_types(Context* ctx, const WabtTypeVector* types) {
- size_t i;
- for (i = 0; i < types->size; ++i)
- push_type(ctx, types->data[i]);
-}
-
-static WabtType peek_type(Context* ctx, size_t depth, int arity) {
- if (arity > 0) {
- if (depth < ctx->type_stack.size - type_stack_limit(ctx)) {
- return ctx->type_stack.data[ctx->type_stack.size - depth - 1];
- } else {
- /* return any type to allow type-checking to continue; the caller should
- * have already raised an error about the stack underflow. */
- return WABT_TYPE_I32;
- }
- } else {
- return WABT_TYPE_VOID;
- }
-}
-
-static WabtType top_type(Context* ctx) {
- return peek_type(ctx, 0, 1);
-}
-
-static WabtType pop_type(Context* ctx) {
- WabtType result = top_type(ctx);
- if (ctx->type_stack.size > type_stack_limit(ctx))
- ctx->type_stack.size--;
- return result;
-}
-
static void check_type(Context* ctx,
const WabtLocation* loc,
WabtType actual,
WabtType expected,
const char* desc) {
- if (actual != expected) {
+ if (expected != actual) {
print_error(ctx, loc, "type mismatch at %s. got %s, expected %s", desc,
wabt_get_type_name(actual), wabt_get_type_name(expected));
}
@@ -372,7 +255,8 @@ static void check_type_index(Context* ctx,
const char* desc,
int index,
const char* index_kind) {
- if (actual != expected) {
+ if (expected != actual && expected != WABT_TYPE_ANY &&
+ actual != WABT_TYPE_ANY) {
print_error(ctx, loc, "type mismatch for %s %d of %s. got %s, expected %s",
index_kind, index, desc, wabt_get_type_name(actual),
wabt_get_type_name(expected));
@@ -419,69 +303,13 @@ static void check_const_type(Context* ctx,
WabtType actual,
const WabtConstVector* expected,
const char* desc) {
- assert(actual != WABT_TYPE_ANY);
WabtTypeVector actual_types;
-
WABT_ZERO_MEMORY(actual_types);
actual_types.size = actual == WABT_TYPE_VOID ? 0 : 1;
actual_types.data = &actual;
check_const_types(ctx, loc, &actual_types, expected, desc);
}
-static void pop_and_check_1_type(Context* ctx,
- const WabtLocation* loc,
- WabtType expected,
- const char* desc) {
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, loc, 1, desc))) {
- WabtType actual = pop_type(ctx);
- check_type(ctx, loc, actual, expected, desc);
- }
-}
-
-static void pop_and_check_2_types(Context* ctx,
- const WabtLocation* loc,
- WabtType expected1,
- WabtType expected2,
- const char* desc) {
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, loc, 2, desc))) {
- WabtType actual2 = pop_type(ctx);
- WabtType actual1 = pop_type(ctx);
- check_type(ctx, loc, actual1, expected1, desc);
- check_type(ctx, loc, actual2, expected2, desc);
- }
-}
-
-static void check_opcode1(Context* ctx,
- const WabtLocation* loc,
- WabtOpcode opcode) {
- pop_and_check_1_type(ctx, loc, wabt_get_opcode_param_type_1(opcode),
- wabt_get_opcode_name(opcode));
- push_type(ctx, wabt_get_opcode_result_type(opcode));
-}
-
-static void check_opcode2(Context* ctx,
- const WabtLocation* loc,
- WabtOpcode opcode) {
- pop_and_check_2_types(ctx, loc, wabt_get_opcode_param_type_1(opcode),
- wabt_get_opcode_param_type_2(opcode),
- wabt_get_opcode_name(opcode));
- push_type(ctx, wabt_get_opcode_result_type(opcode));
-}
-
-static void check_n_types(Context* ctx,
- const WabtLocation* loc,
- const WabtTypeVector* expected,
- const char* desc) {
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, loc, expected->size, desc))) {
- size_t i;
- for (i = 0; i < expected->size; ++i) {
- WabtType actual =
- ctx->type_stack.data[ctx->type_stack.size - expected->size + i];
- check_type(ctx, loc, actual, expected->data[i], desc);
- }
- }
-}
-
static void check_assert_return_nan_type(Context* ctx,
const WabtLocation* loc,
WabtType actual,
@@ -494,75 +322,16 @@ static void check_assert_return_nan_type(Context* ctx,
}
}
-static WabtResult check_br(Context* ctx,
- const WabtLocation* loc,
- const WabtVar* var,
- const WabtBlockSignature** out_sig,
- const char* desc) {
- LabelNode* node;
- WabtResult result = check_label_var(ctx, ctx->top_label, var, &node);
- if (WABT_SUCCEEDED(result)) {
- if (node->label_type != LABEL_TYPE_LOOP) {
- check_n_types(ctx, loc, node->sig, desc);
- }
-
- if (out_sig)
- *out_sig = node->sig;
- }
- return result;
-}
-
-static void check_call(Context* ctx,
- const WabtLocation* loc,
- const WabtStringSlice* callee_name,
- const WabtFuncSignature* sig,
- const char* desc) {
- size_t expected_args = sig->param_types.size;
- size_t limit = type_stack_limit(ctx);
- size_t avail = ctx->type_stack.size - limit;
- size_t i;
- if (expected_args <= avail) {
- for (i = 0; i < sig->param_types.size; ++i) {
- WabtType actual =
- ctx->type_stack.data[ctx->type_stack.size - expected_args + i];
- WabtType expected = sig->param_types.data[i];
- check_type_index(ctx, loc, actual, expected, desc, i, "argument");
- }
- ctx->type_stack.size -= expected_args;
- } else {
- print_error(ctx, loc, "type stack size too small at %s. got %" PRIzd
- ", expected at least %" PRIzd,
- desc, avail, expected_args);
- ctx->type_stack.size = limit;
- }
- for (i = 0; i < sig->result_types.size; ++i)
- push_type(ctx, sig->result_types.data[i]);
-}
-
static void check_expr(Context* ctx, const WabtExpr* expr);
-static void check_block(Context* ctx,
- const WabtLocation* loc,
- const WabtExpr* first,
- const char* desc) {
- WabtBool check_result = WABT_TRUE;
+static void check_expr_list(Context* ctx,
+ const WabtLocation* loc,
+ const WabtExpr* first) {
if (first) {
const WabtExpr* expr;
- for (expr = first; expr; expr = expr->next) {
+ for (expr = first; expr; expr = expr->next)
check_expr(ctx, expr);
- /* stop typechecking if we hit unreachable code */
- if (top_type(ctx) == WABT_TYPE_ANY) {
- check_result = WABT_FALSE;
- break;
- }
- }
}
- if (check_result) {
- assert(ctx->top_label != NULL);
- check_n_types(ctx, loc, ctx->top_label->sig, desc);
- check_type_stack_limit_exact(ctx, loc, ctx->top_label->sig->size, desc);
- }
- ctx->type_stack.size = ctx->top_label->type_stack_limit;
}
static void check_has_memory(Context* ctx,
@@ -575,51 +344,47 @@ static void check_has_memory(Context* ctx,
}
static void check_expr(Context* ctx, const WabtExpr* expr) {
+ ctx->expr_loc = &expr->loc;
+
switch (expr->type) {
case WABT_EXPR_TYPE_BINARY:
- check_opcode2(ctx, &expr->loc, expr->binary.opcode);
+ wabt_typechecker_on_binary(&ctx->typechecker, expr->binary.opcode);
break;
- case WABT_EXPR_TYPE_BLOCK: {
- LabelNode node;
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_BLOCK, &expr->block.sig);
- check_block(ctx, &expr->loc, expr->block.first, "block");
- pop_label(ctx);
- push_types(ctx, &expr->block.sig);
+ case WABT_EXPR_TYPE_BLOCK:
+ wabt_typechecker_on_block(&ctx->typechecker, &expr->block.sig);
+ check_expr_list(ctx, &expr->loc, expr->block.first);
+ wabt_typechecker_on_end(&ctx->typechecker);
break;
- }
case WABT_EXPR_TYPE_BR:
- check_br(ctx, &expr->loc, &expr->br.var, NULL, "br value");
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ wabt_typechecker_on_br(&ctx->typechecker, expr->br.var.index);
break;
- case WABT_EXPR_TYPE_BR_IF: {
- const WabtBlockSignature* sig;
- pop_and_check_1_type(ctx, &expr->loc, WABT_TYPE_I32, "br_if condition");
- check_br(ctx, &expr->loc, &expr->br_if.var, &sig, "br_if value");
+ case WABT_EXPR_TYPE_BR_IF:
+ wabt_typechecker_on_br_if(&ctx->typechecker, expr->br_if.var.index);
break;
- }
case WABT_EXPR_TYPE_BR_TABLE: {
- pop_and_check_1_type(ctx, &expr->loc, WABT_TYPE_I32, "br_table key");
+ wabt_typechecker_begin_br_table(&ctx->typechecker);
size_t i;
for (i = 0; i < expr->br_table.targets.size; ++i) {
- check_br(ctx, &expr->loc, &expr->br_table.targets.data[i], NULL,
- "br_table target");
+ wabt_typechecker_on_br_table_target(
+ &ctx->typechecker, expr->br_table.targets.data[i].index);
}
- check_br(ctx, &expr->loc, &expr->br_table.default_target, NULL,
- "br_table default target");
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ wabt_typechecker_on_br_table_target(&ctx->typechecker,
+ expr->br_table.default_target.index);
+ wabt_typechecker_end_br_table(&ctx->typechecker);
break;
}
case WABT_EXPR_TYPE_CALL: {
const WabtFunc* callee;
- if (WABT_SUCCEEDED(check_func_var(ctx, &expr->call.var, &callee)))
- check_call(ctx, &expr->loc, &callee->name, &callee->decl.sig, "call");
+ if (WABT_SUCCEEDED(check_func_var(ctx, &expr->call.var, &callee))) {
+ wabt_typechecker_on_call(&ctx->typechecker,
+ &callee->decl.sig.param_types,
+ &callee->decl.sig.result_types);
+ }
break;
}
@@ -631,148 +396,118 @@ static void check_expr(Context* ctx, const WabtExpr* expr) {
}
if (WABT_SUCCEEDED(
check_func_type_var(ctx, &expr->call_indirect.var, &func_type))) {
- WabtType type = pop_type(ctx);
- check_type(ctx, &expr->loc, type, WABT_TYPE_I32,
- "call_indirect function index");
- check_call(ctx, &expr->loc, NULL, &func_type->sig, "call_indirect");
+ wabt_typechecker_on_call_indirect(&ctx->typechecker,
+ &func_type->sig.param_types,
+ &func_type->sig.result_types);
}
break;
}
case WABT_EXPR_TYPE_COMPARE:
- check_opcode2(ctx, &expr->loc, expr->compare.opcode);
+ wabt_typechecker_on_compare(&ctx->typechecker, expr->compare.opcode);
break;
case WABT_EXPR_TYPE_CONST:
- push_type(ctx, expr->const_.type);
+ wabt_typechecker_on_const(&ctx->typechecker, expr->const_.type);
break;
case WABT_EXPR_TYPE_CONVERT:
- check_opcode1(ctx, &expr->loc, expr->convert.opcode);
+ wabt_typechecker_on_convert(&ctx->typechecker, expr->convert.opcode);
break;
case WABT_EXPR_TYPE_DROP:
- if (WABT_SUCCEEDED(check_type_stack_limit(ctx, &expr->loc, 1, "drop")))
- pop_type(ctx);
+ wabt_typechecker_on_drop(&ctx->typechecker);
break;
- case WABT_EXPR_TYPE_GET_GLOBAL: {
- const WabtGlobal* global;
- if (WABT_SUCCEEDED(
- check_global_var(ctx, &expr->get_global.var, &global, NULL)))
- push_type(ctx, global->type);
+ case WABT_EXPR_TYPE_GET_GLOBAL:
+ wabt_typechecker_on_get_global(
+ &ctx->typechecker,
+ get_global_var_type_or_any(ctx, &expr->get_global.var));
break;
- }
- case WABT_EXPR_TYPE_GET_LOCAL: {
- WabtType type;
- if (WABT_SUCCEEDED(check_local_var(ctx, &expr->get_local.var, &type)))
- push_type(ctx, type);
+ case WABT_EXPR_TYPE_GET_LOCAL:
+ wabt_typechecker_on_get_local(
+ &ctx->typechecker,
+ get_local_var_type_or_any(ctx, &expr->get_local.var));
break;
- }
case WABT_EXPR_TYPE_GROW_MEMORY:
check_has_memory(ctx, &expr->loc, WABT_OPCODE_GROW_MEMORY);
- check_opcode1(ctx, &expr->loc, WABT_OPCODE_GROW_MEMORY);
+ wabt_typechecker_on_grow_memory(&ctx->typechecker);
break;
- case WABT_EXPR_TYPE_IF: {
- LabelNode node;
- pop_and_check_1_type(ctx, &expr->loc, WABT_TYPE_I32, "if condition");
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_IF, &expr->if_.true_.sig);
- check_block(ctx, &expr->loc, expr->if_.true_.first, "if true branch");
- check_block(ctx, &expr->loc, expr->if_.false_, "if false branch");
- pop_label(ctx);
- push_types(ctx, &expr->if_.true_.sig);
+ case WABT_EXPR_TYPE_IF:
+ wabt_typechecker_on_if(&ctx->typechecker, &expr->if_.true_.sig);
+ check_expr_list(ctx, &expr->loc, expr->if_.true_.first);
+ if (expr->if_.false_) {
+ wabt_typechecker_on_else(&ctx->typechecker);
+ check_expr_list(ctx, &expr->loc, expr->if_.false_);
+ }
+ wabt_typechecker_on_end(&ctx->typechecker);
break;
- }
case WABT_EXPR_TYPE_LOAD:
check_has_memory(ctx, &expr->loc, expr->load.opcode);
check_align(ctx, &expr->loc, expr->load.align,
get_opcode_natural_alignment(expr->load.opcode));
check_offset(ctx, &expr->loc, expr->load.offset);
- check_opcode1(ctx, &expr->loc, expr->load.opcode);
+ wabt_typechecker_on_load(&ctx->typechecker, expr->load.opcode);
break;
- case WABT_EXPR_TYPE_LOOP: {
- LabelNode node;
- push_label(ctx, &expr->loc, &node, LABEL_TYPE_LOOP, &expr->loop.sig);
- check_block(ctx, &expr->loc, expr->loop.first, "loop");
- pop_label(ctx);
- push_types(ctx, &expr->block.sig);
+ case WABT_EXPR_TYPE_LOOP:
+ wabt_typechecker_on_loop(&ctx->typechecker, &expr->loop.sig);
+ check_expr_list(ctx, &expr->loc, expr->loop.first);
+ wabt_typechecker_on_end(&ctx->typechecker);
break;
- }
case WABT_EXPR_TYPE_CURRENT_MEMORY:
check_has_memory(ctx, &expr->loc, WABT_OPCODE_CURRENT_MEMORY);
- push_type(ctx, WABT_TYPE_I32);
+ wabt_typechecker_on_current_memory(&ctx->typechecker);
break;
case WABT_EXPR_TYPE_NOP:
break;
- case WABT_EXPR_TYPE_RETURN: {
- check_n_types(ctx, &expr->loc, &ctx->current_func->decl.sig.result_types,
- "return");
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ case WABT_EXPR_TYPE_RETURN:
+ wabt_typechecker_on_return(&ctx->typechecker);
break;
- }
- case WABT_EXPR_TYPE_SELECT: {
- pop_and_check_1_type(ctx, &expr->loc, WABT_TYPE_I32, "select");
- if (WABT_SUCCEEDED(
- check_type_stack_limit(ctx, &expr->loc, 2, "select"))) {
- WabtType type1 = pop_type(ctx);
- WabtType type2 = pop_type(ctx);
- check_type(ctx, &expr->loc, type2, type1, "select");
- push_type(ctx, type1);
- }
+ case WABT_EXPR_TYPE_SELECT:
+ wabt_typechecker_on_select(&ctx->typechecker);
break;
- }
- case WABT_EXPR_TYPE_SET_GLOBAL: {
- WabtType type = WABT_TYPE_I32;
- const WabtGlobal* global;
- if (WABT_SUCCEEDED(
- check_global_var(ctx, &expr->set_global.var, &global, NULL))) {
- type = global->type;
- }
- pop_and_check_1_type(ctx, &expr->loc, type, "set_global");
+ case WABT_EXPR_TYPE_SET_GLOBAL:
+ wabt_typechecker_on_set_global(
+ &ctx->typechecker,
+ get_global_var_type_or_any(ctx, &expr->set_global.var));
break;
- }
- case WABT_EXPR_TYPE_SET_LOCAL: {
- WabtType type = WABT_TYPE_I32;
- check_local_var(ctx, &expr->set_local.var, &type);
- pop_and_check_1_type(ctx, &expr->loc, type, "set_local");
+ case WABT_EXPR_TYPE_SET_LOCAL:
+ wabt_typechecker_on_set_local(
+ &ctx->typechecker,
+ get_local_var_type_or_any(ctx, &expr->set_local.var));
break;
- }
case WABT_EXPR_TYPE_STORE:
check_has_memory(ctx, &expr->loc, expr->store.opcode);
check_align(ctx, &expr->loc, expr->store.align,
get_opcode_natural_alignment(expr->store.opcode));
check_offset(ctx, &expr->loc, expr->store.offset);
- check_opcode2(ctx, &expr->loc, expr->store.opcode);
+ wabt_typechecker_on_store(&ctx->typechecker, expr->store.opcode);
break;
- case WABT_EXPR_TYPE_TEE_LOCAL: {
- WabtType local_type = WABT_TYPE_I32;
- check_local_var(ctx, &expr->tee_local.var, &local_type);
- if (check_type_stack_limit(ctx, &expr->loc, 1, "tee_local"))
- check_type(ctx, &expr->loc, top_type(ctx), local_type, "tee_local");
+ case WABT_EXPR_TYPE_TEE_LOCAL:
+ wabt_typechecker_on_tee_local(
+ &ctx->typechecker,
+ get_local_var_type_or_any(ctx, &expr->tee_local.var));
break;
- }
case WABT_EXPR_TYPE_UNARY:
- check_opcode1(ctx, &expr->loc, expr->unary.opcode);
+ wabt_typechecker_on_unary(&ctx->typechecker, expr->unary.opcode);
break;
case WABT_EXPR_TYPE_UNREACHABLE:
- reset_type_stack_to_limit(ctx);
- push_type(ctx, WABT_TYPE_ANY);
+ wabt_typechecker_on_unreachable(&ctx->typechecker);
break;
}
}
@@ -806,12 +541,11 @@ static void check_func(Context* ctx,
}
}
- /* The function has an implicit label; branching to it is equivalent to the
- * returning from the function. */
- LabelNode node;
- push_label(ctx, loc, &node, LABEL_TYPE_FUNC, &func->decl.sig.result_types);
- check_block(ctx, loc, func->first_expr, "function");
- pop_label(ctx);
+ ctx->expr_loc = loc;
+ wabt_typechecker_begin_function(&ctx->typechecker,
+ &func->decl.sig.result_types);
+ check_expr_list(ctx, loc, func->first_expr);
+ wabt_typechecker_end_function(&ctx->typechecker);
ctx->current_func = NULL;
}
@@ -1294,7 +1028,7 @@ static void check_command(Context* ctx, const WabtCommand* command) {
}
static void wabt_destroy_context(Context* ctx) {
- wabt_destroy_type_vector(ctx->allocator, &ctx->type_stack);
+ wabt_destroy_typechecker(&ctx->typechecker);
}
WabtResult wabt_validate_script(WabtAllocator* allocator,
@@ -1308,6 +1042,13 @@ WabtResult wabt_validate_script(WabtAllocator* allocator,
ctx.error_handler = error_handler;
ctx.result = WABT_OK;
ctx.script = script;
+
+ WabtTypeCheckerErrorHandler tc_error_handler;
+ tc_error_handler.on_error = on_typechecker_error;
+ tc_error_handler.user_data = &ctx;
+ ctx.typechecker.allocator = allocator;
+ ctx.typechecker.error_handler = &tc_error_handler;
+
size_t i;
for (i = 0; i < script->commands.size; ++i)
check_command(&ctx, &script->commands.data[i]);
diff --git a/test/interp/if-then-br.txt b/test/interp/if-then-br.txt
deleted file mode 100644
index 3f16f157..00000000
--- a/test/interp/if-then-br.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-;;; TOOL: run-interp
-
-;; This used to test an odd case that forced dropping the (i32.const 3) of the
-;; else branch. Now that drops are explicit, this case is straightforward.
-
-(module
- (func $f (param i32) (result i32)
- (local i32)
- get_local 0
- if $l
- br $l
- i32.const 2
- else
- i32.const 3
- drop
- end
- i32.const 2)
-
- (func (export "e1") (result i32)
- i32.const 0
- call $f)
-
- (func (export "e2") (result i32)
- i32.const 1
- call $f))
-(;; STDOUT ;;;
-e1() => i32:2
-e2() => i32:2
-;;; STDOUT ;;)
diff --git a/test/parse/expr/bad-binary-one-expr.txt b/test/parse/expr/bad-binary-one-expr.txt
index fdf815f6..f7472436 100644
--- a/test/parse/expr/bad-binary-one-expr.txt
+++ b/test/parse/expr/bad-binary-one-expr.txt
@@ -6,7 +6,7 @@
out/test/parse/expr/bad-binary-one-expr.txt:4:4: type stack size too small at i32.add. got 1, expected at least 2
i32.add))
^^^^^^^
-out/test/parse/expr/bad-binary-one-expr.txt:2:9: type stack at end of function is 2. expected 0
-(module (func
- ^^^
+out/test/parse/expr/bad-binary-one-expr.txt:4:4: type stack at end of function is 1, expected 0
+ i32.add))
+ ^^^^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-br-bad-depth.txt b/test/parse/expr/bad-br-bad-depth.txt
index e6d4ab4c..ffd55f75 100644
--- a/test/parse/expr/bad-br-bad-depth.txt
+++ b/test/parse/expr/bad-br-bad-depth.txt
@@ -7,7 +7,7 @@
end
end))
(;; STDERR ;;;
-out/test/parse/expr/bad-br-bad-depth.txt:6:12: label variable out of range (max 3)
+out/test/parse/expr/bad-br-bad-depth.txt:6:9: invalid depth: 3 (max 2)
br 3
- ^
+ ^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-br-defined-later.txt b/test/parse/expr/bad-br-defined-later.txt
index eaceaedc..82f215da 100644
--- a/test/parse/expr/bad-br-defined-later.txt
+++ b/test/parse/expr/bad-br-defined-later.txt
@@ -6,7 +6,7 @@
nop
end))
(;; STDERR ;;;
-out/test/parse/expr/bad-br-defined-later.txt:4:8: label variable out of range (max 1)
+out/test/parse/expr/bad-br-defined-later.txt:4:5: invalid depth: 1 (max 0)
br 1
- ^
+ ^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-br-undefined.txt b/test/parse/expr/bad-br-undefined.txt
index 80acf302..817ed38b 100644
--- a/test/parse/expr/bad-br-undefined.txt
+++ b/test/parse/expr/bad-br-undefined.txt
@@ -1,7 +1,7 @@
;;; ERROR: 1
(module (func br 1))
(;; STDERR ;;;
-out/test/parse/expr/bad-br-undefined.txt:2:18: label variable out of range (max 1)
+out/test/parse/expr/bad-br-undefined.txt:2:15: invalid depth: 1 (max 0)
(module (func br 1))
- ^
+ ^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-brtable-bad-depth.txt b/test/parse/expr/bad-brtable-bad-depth.txt
index 9360224e..e375ae4f 100644
--- a/test/parse/expr/bad-brtable-bad-depth.txt
+++ b/test/parse/expr/bad-brtable-bad-depth.txt
@@ -6,7 +6,7 @@
br_table 2
end))
(;; STDERR ;;;
-out/test/parse/expr/bad-brtable-bad-depth.txt:6:16: label variable out of range (max 2)
+out/test/parse/expr/bad-brtable-bad-depth.txt:6:7: invalid depth: 2 (max 1)
br_table 2
- ^
+ ^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-compare-one-expr.txt b/test/parse/expr/bad-compare-one-expr.txt
index dc7aa5e5..7688b6db 100644
--- a/test/parse/expr/bad-compare-one-expr.txt
+++ b/test/parse/expr/bad-compare-one-expr.txt
@@ -6,7 +6,7 @@
out/test/parse/expr/bad-compare-one-expr.txt:4:11: type stack size too small at i32.lt_s. got 1, expected at least 2
i32.lt_s))
^^^^^^^^
-out/test/parse/expr/bad-compare-one-expr.txt:2:9: type stack at end of function is 2. expected 0
-(module (func
- ^^^^^
+out/test/parse/expr/bad-compare-one-expr.txt:4:11: type stack at end of function is 1, expected 0
+ i32.lt_s))
+ ^^^^^^^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-getglobal-name-undefined.txt b/test/parse/expr/bad-getglobal-name-undefined.txt
index 93235d15..54cd35e5 100644
--- a/test/parse/expr/bad-getglobal-name-undefined.txt
+++ b/test/parse/expr/bad-getglobal-name-undefined.txt
@@ -1,7 +1,7 @@
;;; ERROR: 1
-(module (func get_global 0))
+(module (func get_global $n))
(;; STDERR ;;;
-out/test/parse/expr/bad-getglobal-name-undefined.txt:2:26: global variable out of range (max 0)
-(module (func get_global 0))
- ^
+out/test/parse/expr/bad-getglobal-name-undefined.txt:2:26: undefined global variable "$n"
+(module (func get_global $n))
+ ^^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-getglobal-undefined.txt b/test/parse/expr/bad-getglobal-undefined.txt
index 7f108b19..bd2e9598 100644
--- a/test/parse/expr/bad-getglobal-undefined.txt
+++ b/test/parse/expr/bad-getglobal-undefined.txt
@@ -1,7 +1,10 @@
;;; ERROR: 1
-(module (func get_global 0))
+(module
+ (func
+ get_global 0
+ drop))
(;; STDERR ;;;
-out/test/parse/expr/bad-getglobal-undefined.txt:2:26: global variable out of range (max 0)
-(module (func get_global 0))
- ^
+out/test/parse/expr/bad-getglobal-undefined.txt:4:16: global variable out of range (max 0)
+ get_global 0
+ ^
;;; STDERR ;;)
diff --git a/test/parse/expr/bad-getlocal-undefined.txt b/test/parse/expr/bad-getlocal-undefined.txt
index f647c2c7..2b32d942 100644
--- a/test/parse/expr/bad-getlocal-undefined.txt
+++ b/test/parse/expr/bad-getlocal-undefined.txt
@@ -1,7 +1,10 @@
;;; ERROR: 1
-(module (func (get_local 0)))
+(module
+ (func
+ get_local 0
+ drop))
(;; STDERR ;;;
-out/test/parse/expr/bad-getlocal-undefined.txt:2:26: local variable out of range (max 0)
-(module (func (get_local 0)))
- ^
+out/test/parse/expr/bad-getlocal-undefined.txt:4:15: local variable out of range (max 0)
+ get_local 0
+ ^
;;; STDERR ;;)
diff --git a/test/parse/func/bad-sig-result-type-mismatch.txt b/test/parse/func/bad-sig-result-type-mismatch.txt
index d4c6dbdb..ce0800b9 100644
--- a/test/parse/func/bad-sig-result-type-mismatch.txt
+++ b/test/parse/func/bad-sig-result-type-mismatch.txt
@@ -6,10 +6,7 @@
out/test/parse/func/bad-sig-result-type-mismatch.txt:4:3: type mismatch for result 0 of function. got i64, expected f32
(func (type $t) (param i32) (result i64)))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-out/test/parse/func/bad-sig-result-type-mismatch.txt:4:3: type stack size too small at function. got 0, expected at least 1
- (func (type $t) (param i32) (result i64)))
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-out/test/parse/func/bad-sig-result-type-mismatch.txt:4:3: type stack at end of function is 0. expected 1
+out/test/parse/func/bad-sig-result-type-mismatch.txt:4:3: type stack size too small at implicit return. got 0, expected at least 1
(func (type $t) (param i32) (result i64)))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/parse/func/bad-sig-result-type-not-void.txt b/test/parse/func/bad-sig-result-type-not-void.txt
index bc59176f..3d751f3e 100644
--- a/test/parse/func/bad-sig-result-type-not-void.txt
+++ b/test/parse/func/bad-sig-result-type-not-void.txt
@@ -6,10 +6,7 @@
out/test/parse/func/bad-sig-result-type-not-void.txt:4:3: expected 0 results, got 1
(func (type $t) (param i32) (result f32)))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-out/test/parse/func/bad-sig-result-type-not-void.txt:4:3: type stack size too small at function. got 0, expected at least 1
- (func (type $t) (param i32) (result f32)))
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-out/test/parse/func/bad-sig-result-type-not-void.txt:4:3: type stack at end of function is 0. expected 1
+out/test/parse/func/bad-sig-result-type-not-void.txt:4:3: type stack size too small at implicit return. got 0, expected at least 1
(func (type $t) (param i32) (result f32)))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/regress/regress-5.txt b/test/regress/regress-5.txt
index f3732b0c..a95d06c4 100644
--- a/test/regress/regress-5.txt
+++ b/test/regress/regress-5.txt
@@ -117,7 +117,7 @@
(i64.const 0)) ;; deliberate type-check error
)
(;; STDERR ;;;
-out/test/regress/regress-5.txt:116:3: type mismatch at function. got i64, expected i32
- (func (result i32)
- ^^^^^^^^^^^^^^^^
+out/test/regress/regress-5.txt:117:6: type mismatch in implicit return, expected i32 but got i64.
+ (i64.const 0)) ;; deliberate type-check error
+ ^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/spec/block.txt b/test/spec/block.txt
index 394f51b4..80a34a59 100644
--- a/test/spec/block.txt
+++ b/test/spec/block.txt
@@ -14,13 +14,13 @@ out/third_party/testsuite/block.wast:145: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x0000001c: end_function_body callback failed
out/third_party/testsuite/block.wast:150: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x0000001c: on_end_expr callback failed
out/third_party/testsuite/block.wast:156: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x0000001d: end_function_body callback failed
out/third_party/testsuite/block.wast:162: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x00000020: on_end_expr callback failed
out/third_party/testsuite/block.wast:169: assert_invalid passed:
error: type stack size too small at br. got 0, expected at least 1
@@ -29,11 +29,11 @@ out/third_party/testsuite/block.wast:175: assert_invalid passed:
error: type stack size too small at br. got 0, expected at least 1
error: @0x0000001c: on_br_expr callback failed
out/third_party/testsuite/block.wast:182: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000021: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
out/third_party/testsuite/block.wast:188: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000022: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000021: on_end_expr callback failed
out/third_party/testsuite/block.wast:194: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x00000023: end_function_body callback failed
@@ -41,7 +41,7 @@ out/third_party/testsuite/block.wast:200: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x00000024: end_function_body callback failed
out/third_party/testsuite/block.wast:207: assert_invalid passed:
- error: type stack at end of func is 1. expected 0
+ error: type stack at end of function is 1, expected 0
error: @0x00000024: end_function_body callback failed
out/third_party/testsuite/block.wast:213: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
diff --git a/test/spec/br.txt b/test/spec/br.txt
index a88275b5..acf2ce52 100644
--- a/test/spec/br.txt
+++ b/test/spec/br.txt
@@ -2,22 +2,22 @@
;;; STDIN_FILE: third_party/testsuite/br.wast
(;; STDOUT ;;;
out/third_party/testsuite/br.wast:372: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000020: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x0000001f: on_end_expr callback failed
out/third_party/testsuite/br.wast:379: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000021: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
out/third_party/testsuite/br.wast:385: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000022: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000021: on_end_expr callback failed
out/third_party/testsuite/br.wast:392: assert_invalid passed:
- error: invalid depth: 1 (max 1)
+ error: invalid depth: 1 (max 0)
error: @0x00000019: on_br_expr callback failed
out/third_party/testsuite/br.wast:396: assert_invalid passed:
- error: invalid depth: 5 (max 3)
+ error: invalid depth: 5 (max 2)
error: @0x0000001d: on_br_expr callback failed
out/third_party/testsuite/br.wast:400: assert_invalid passed:
- error: invalid depth: 268435457 (max 1)
+ error: invalid depth: 268435457 (max 0)
error: @0x0000001d: on_br_expr callback failed
67/67 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/br_if.txt b/test/spec/br_if.txt
index 5e9adef3..ee715d67 100644
--- a/test/spec/br_if.txt
+++ b/test/spec/br_if.txt
@@ -32,10 +32,10 @@ out/third_party/testsuite/br_if.wast:211: assert_invalid passed:
error: type stack size too small at br_if. got 0, expected at least 1
error: @0x0000001e: on_br_if_expr callback failed
out/third_party/testsuite/br_if.wast:217: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x00000020: on_end_expr callback failed
out/third_party/testsuite/br_if.wast:223: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x00000020: on_end_expr callback failed
out/third_party/testsuite/br_if.wast:230: assert_invalid passed:
error: type stack size too small at br_if. got 0, expected at least 1
@@ -62,13 +62,13 @@ out/third_party/testsuite/br_if.wast:273: assert_invalid passed:
error: type mismatch in br_if, expected i32 but got i64.
error: @0x00000020: on_br_if_expr callback failed
out/third_party/testsuite/br_if.wast:280: assert_invalid passed:
- error: invalid depth: 1 (max 1)
+ error: invalid depth: 1 (max 0)
error: @0x0000001b: on_br_if_expr callback failed
out/third_party/testsuite/br_if.wast:284: assert_invalid passed:
- error: invalid depth: 5 (max 3)
+ error: invalid depth: 5 (max 2)
error: @0x0000001f: on_br_if_expr callback failed
out/third_party/testsuite/br_if.wast:288: assert_invalid passed:
- error: invalid depth: 268435457 (max 1)
+ error: invalid depth: 268435457 (max 0)
error: @0x0000001f: on_br_if_expr callback failed
57/57 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/br_table.txt b/test/spec/br_table.txt
index 21ee927c..0f6c0e15 100644
--- a/test/spec/br_table.txt
+++ b/test/spec/br_table.txt
@@ -2,8 +2,8 @@
;;; STDIN_FILE: third_party/testsuite/br_table.wast
(;; STDOUT ;;;
out/third_party/testsuite/br_table.wast:1386: assert_invalid passed:
- error: type stack size too small at implicit return. got 0, expected at least 1
- error: @0x00000023: end_function_body callback failed
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000022: on_end_expr callback failed
out/third_party/testsuite/br_table.wast:1393: assert_invalid passed:
error: type stack size too small at br_table. got 0, expected at least 1
error: @0x00000020: on_br_table_expr callback failed
@@ -23,22 +23,22 @@ out/third_party/testsuite/br_table.wast:1424: assert_invalid passed:
error: type mismatch in br_table, expected i32 but got i64.
error: @0x00000022: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1431: assert_invalid passed:
- error: invalid depth: 2 (max 2)
+ error: invalid depth: 2 (max 1)
error: @0x0000001f: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1437: assert_invalid passed:
- error: invalid depth: 5 (max 3)
+ error: invalid depth: 5 (max 2)
error: @0x00000021: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1443: assert_invalid passed:
- error: invalid depth: 268435457 (max 2)
+ error: invalid depth: 268435457 (max 1)
error: @0x00000024: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1450: assert_invalid passed:
- error: invalid depth: 2 (max 2)
+ error: invalid depth: 2 (max 1)
error: @0x0000001f: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1456: assert_invalid passed:
- error: invalid depth: 5 (max 3)
+ error: invalid depth: 5 (max 2)
error: @0x00000021: on_br_table_expr callback failed
out/third_party/testsuite/br_table.wast:1462: assert_invalid passed:
- error: invalid depth: 268435457 (max 2)
+ error: invalid depth: 268435457 (max 1)
error: @0x00000024: on_br_table_expr callback failed
156/156 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/call.txt b/test/spec/call.txt
index ce675d86..467f92cd 100644
--- a/test/spec/call.txt
+++ b/test/spec/call.txt
@@ -14,10 +14,10 @@ out/third_party/testsuite/call.wast:173: assert_invalid passed:
error: type stack size too small at call. got 0, expected at least 2
error: @0x0000001f: on_call_expr callback failed
out/third_party/testsuite/call.wast:180: assert_invalid passed:
- error: type stack at end of func is 1. expected 0
+ error: type stack at end of function is 1, expected 0
error: @0x0000001d: end_function_body callback failed
out/third_party/testsuite/call.wast:187: assert_invalid passed:
- error: type stack at end of func is 2. expected 0
+ error: type stack at end of function is 2, expected 0
error: @0x00000026: end_function_body callback failed
out/third_party/testsuite/call.wast:195: assert_invalid passed:
error: type stack size too small at call. got 1, expected at least 2
@@ -26,9 +26,11 @@ out/third_party/testsuite/call.wast:202: assert_invalid passed:
error: type stack size too small at call. got 1, expected at least 2
error: @0x00000022: on_call_expr callback failed
out/third_party/testsuite/call.wast:209: assert_invalid passed:
+ error: type mismatch in call, expected i32 but got f64.
error: type mismatch in call, expected f64 but got i32.
error: @0x0000002a: on_call_expr callback failed
out/third_party/testsuite/call.wast:216: assert_invalid passed:
+ error: type mismatch in call, expected f64 but got i32.
error: type mismatch in call, expected i32 but got f64.
error: @0x0000002a: on_call_expr callback failed
out/third_party/testsuite/call.wast:227: assert_invalid passed:
diff --git a/test/spec/call_indirect.txt b/test/spec/call_indirect.txt
index 59773f0c..8a957286 100644
--- a/test/spec/call_indirect.txt
+++ b/test/spec/call_indirect.txt
@@ -17,10 +17,10 @@ out/third_party/testsuite/call_indirect.wast:262: assert_invalid passed:
error: type stack size too small at call_indirect. got 0, expected at least 2
error: @0x00000027: on_call_indirect_expr callback failed
out/third_party/testsuite/call_indirect.wast:270: assert_invalid passed:
- error: type stack at end of func is 1. expected 0
+ error: type stack at end of function is 1, expected 0
error: @0x00000025: end_function_body callback failed
out/third_party/testsuite/call_indirect.wast:278: assert_invalid passed:
- error: type stack at end of func is 2. expected 0
+ error: type stack at end of function is 2, expected 0
error: @0x0000002e: end_function_body callback failed
out/third_party/testsuite/call_indirect.wast:289: assert_invalid passed:
error: type stack size too small at call_indirect. got 0, expected at least 1
@@ -35,9 +35,11 @@ out/third_party/testsuite/call_indirect.wast:316: assert_invalid passed:
error: type stack size too small at call_indirect. got 1, expected at least 2
error: @0x0000002a: on_call_indirect_expr callback failed
out/third_party/testsuite/call_indirect.wast:326: assert_invalid passed:
+ error: type mismatch in call_indirect, expected i32 but got f64.
error: type mismatch in call_indirect, expected f64 but got i32.
error: @0x00000032: on_call_indirect_expr callback failed
out/third_party/testsuite/call_indirect.wast:336: assert_invalid passed:
+ error: type mismatch in call_indirect, expected f64 but got i32.
error: type mismatch in call_indirect, expected i32 but got f64.
error: @0x00000032: on_call_indirect_expr callback failed
out/third_party/testsuite/call_indirect.wast:350: assert_invalid passed:
diff --git a/test/spec/func.txt b/test/spec/func.txt
index e43ff04e..eeba7f6a 100644
--- a/test/spec/func.txt
+++ b/test/spec/func.txt
@@ -39,7 +39,7 @@ out/third_party/testsuite/func.wast:377: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x0000001a: end_function_body callback failed
out/third_party/testsuite/func.wast:383: assert_invalid passed:
- error: type stack at end of func is 1. expected 0
+ error: type stack at end of function is 1, expected 0
error: @0x0000001a: end_function_body callback failed
out/third_party/testsuite/func.wast:389: assert_invalid passed:
error: type mismatch in implicit return, expected i32 but got f32.
diff --git a/test/spec/labels.txt b/test/spec/labels.txt
index bf881895..7cd376a4 100644
--- a/test/spec/labels.txt
+++ b/test/spec/labels.txt
@@ -5,10 +5,10 @@ out/third_party/testsuite/labels.wast:298: assert_invalid passed:
error: type stack size too small at f32.neg. got 0, expected at least 1
error: @0x0000001e: on_unary_expr callback failed
out/third_party/testsuite/labels.wast:302: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x00000023: on_end_expr callback failed
out/third_party/testsuite/labels.wast:306: assert_invalid passed:
- error: type stack at end of block is 1. expected 0
+ error: type stack at end of block is 1, expected 0
error: @0x00000023: on_end_expr callback failed
27/27 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/loop.txt b/test/spec/loop.txt
index 7d036ea1..8a87a638 100644
--- a/test/spec/loop.txt
+++ b/test/spec/loop.txt
@@ -17,7 +17,7 @@ out/third_party/testsuite/loop.wast:243: assert_invalid passed:
error: type stack size too small at implicit return. got 0, expected at least 1
error: @0x0000001d: end_function_body callback failed
out/third_party/testsuite/loop.wast:249: assert_invalid passed:
- error: type stack at end of loop is 1. expected 0
+ error: type stack at end of loop is 1, expected 0
error: @0x00000020: on_end_expr callback failed
48/48 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/switch.txt b/test/spec/switch.txt
index 18ebfbc2..3a2442fb 100644
--- a/test/spec/switch.txt
+++ b/test/spec/switch.txt
@@ -2,7 +2,7 @@
;;; STDIN_FILE: third_party/testsuite/switch.wast
(;; STDOUT ;;;
out/third_party/testsuite/switch.wast:150: assert_invalid passed:
- error: invalid depth: 3 (max 1)
+ error: invalid depth: 3 (max 0)
error: @0x0000001c: on_br_table_expr callback failed
27/27 tests passed.
;;; STDOUT ;;)
diff --git a/test/spec/typecheck.txt b/test/spec/typecheck.txt
index 7f7be9cd..cfda21db 100644
--- a/test/spec/typecheck.txt
+++ b/test/spec/typecheck.txt
@@ -165,6 +165,7 @@ out/third_party/testsuite/typecheck.wast:274: assert_invalid passed:
error: @0x00000026: on_store_expr callback failed
out/third_party/testsuite/typecheck.wast:275: assert_invalid passed:
error: type mismatch in i64.store, expected i32 but got f32.
+ error: type mismatch in i64.store, expected i64 but got i32.
error: @0x00000026: on_store_expr callback failed
out/third_party/testsuite/typecheck.wast:276: assert_invalid passed:
error: type mismatch in i64.store8, expected i32 but got f32.
@@ -210,135 +211,179 @@ out/third_party/testsuite/typecheck.wast:291: assert_invalid passed:
error: @0x00000023: on_store_expr callback failed
out/third_party/testsuite/typecheck.wast:294: assert_invalid passed:
error: type mismatch in i32.add, expected i32 but got i64.
+ error: type mismatch in i32.add, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:295: assert_invalid passed:
error: type mismatch in i32.and, expected i32 but got i64.
+ error: type mismatch in i32.and, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:296: assert_invalid passed:
error: type mismatch in i32.div_s, expected i32 but got i64.
+ error: type mismatch in i32.div_s, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:297: assert_invalid passed:
error: type mismatch in i32.div_u, expected i32 but got i64.
+ error: type mismatch in i32.div_u, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:298: assert_invalid passed:
error: type mismatch in i32.mul, expected i32 but got i64.
+ error: type mismatch in i32.mul, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:299: assert_invalid passed:
error: type mismatch in i32.or, expected i32 but got i64.
+ error: type mismatch in i32.or, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:300: assert_invalid passed:
error: type mismatch in i32.rem_s, expected i32 but got i64.
+ error: type mismatch in i32.rem_s, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:301: assert_invalid passed:
error: type mismatch in i32.rem_u, expected i32 but got i64.
+ error: type mismatch in i32.rem_u, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:302: assert_invalid passed:
error: type mismatch in i32.rotl, expected i32 but got i64.
+ error: type mismatch in i32.rotl, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:303: assert_invalid passed:
error: type mismatch in i32.rotr, expected i32 but got i64.
+ error: type mismatch in i32.rotr, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:304: assert_invalid passed:
error: type mismatch in i32.shl, expected i32 but got i64.
+ error: type mismatch in i32.shl, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:305: assert_invalid passed:
error: type mismatch in i32.shr_s, expected i32 but got i64.
+ error: type mismatch in i32.shr_s, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:306: assert_invalid passed:
error: type mismatch in i32.shr_u, expected i32 but got i64.
+ error: type mismatch in i32.shr_u, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:307: assert_invalid passed:
error: type mismatch in i32.sub, expected i32 but got i64.
+ error: type mismatch in i32.sub, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:308: assert_invalid passed:
error: type mismatch in i32.xor, expected i32 but got i64.
+ error: type mismatch in i32.xor, expected i32 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:309: assert_invalid passed:
error: type mismatch in i64.add, expected i64 but got i32.
+ error: type mismatch in i64.add, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:310: assert_invalid passed:
error: type mismatch in i64.and, expected i64 but got i32.
+ error: type mismatch in i64.and, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:311: assert_invalid passed:
error: type mismatch in i64.div_s, expected i64 but got i32.
+ error: type mismatch in i64.div_s, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:312: assert_invalid passed:
error: type mismatch in i64.div_u, expected i64 but got i32.
+ error: type mismatch in i64.div_u, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:313: assert_invalid passed:
error: type mismatch in i64.mul, expected i64 but got i32.
+ error: type mismatch in i64.mul, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:314: assert_invalid passed:
error: type mismatch in i64.or, expected i64 but got i32.
+ error: type mismatch in i64.or, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:315: assert_invalid passed:
error: type mismatch in i64.rem_s, expected i64 but got i32.
+ error: type mismatch in i64.rem_s, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:316: assert_invalid passed:
error: type mismatch in i64.rem_u, expected i64 but got i32.
+ error: type mismatch in i64.rem_u, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:317: assert_invalid passed:
error: type mismatch in i64.rotl, expected i64 but got i32.
+ error: type mismatch in i64.rotl, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:318: assert_invalid passed:
error: type mismatch in i64.rotr, expected i64 but got i32.
+ error: type mismatch in i64.rotr, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:319: assert_invalid passed:
error: type mismatch in i64.shl, expected i64 but got i32.
+ error: type mismatch in i64.shl, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:320: assert_invalid passed:
error: type mismatch in i64.shr_s, expected i64 but got i32.
+ error: type mismatch in i64.shr_s, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:321: assert_invalid passed:
error: type mismatch in i64.shr_u, expected i64 but got i32.
+ error: type mismatch in i64.shr_u, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:322: assert_invalid passed:
error: type mismatch in i64.sub, expected i64 but got i32.
+ error: type mismatch in i64.sub, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:323: assert_invalid passed:
error: type mismatch in i64.xor, expected i64 but got i32.
+ error: type mismatch in i64.xor, expected i64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:324: assert_invalid passed:
error: type mismatch in f32.add, expected f32 but got i64.
+ error: type mismatch in f32.add, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:325: assert_invalid passed:
error: type mismatch in f32.copysign, expected f32 but got i64.
+ error: type mismatch in f32.copysign, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:326: assert_invalid passed:
error: type mismatch in f32.div, expected f32 but got i64.
+ error: type mismatch in f32.div, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:327: assert_invalid passed:
error: type mismatch in f32.max, expected f32 but got i64.
+ error: type mismatch in f32.max, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:328: assert_invalid passed:
error: type mismatch in f32.min, expected f32 but got i64.
+ error: type mismatch in f32.min, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:329: assert_invalid passed:
error: type mismatch in f32.mul, expected f32 but got i64.
+ error: type mismatch in f32.mul, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:330: assert_invalid passed:
error: type mismatch in f32.sub, expected f32 but got i64.
+ error: type mismatch in f32.sub, expected f32 but got f64.
error: @0x00000023: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:331: assert_invalid passed:
error: type mismatch in f64.add, expected f64 but got i64.
+ error: type mismatch in f64.add, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:332: assert_invalid passed:
error: type mismatch in f64.copysign, expected f64 but got i64.
+ error: type mismatch in f64.copysign, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:333: assert_invalid passed:
error: type mismatch in f64.div, expected f64 but got i64.
+ error: type mismatch in f64.div, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:334: assert_invalid passed:
error: type mismatch in f64.max, expected f64 but got i64.
+ error: type mismatch in f64.max, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:335: assert_invalid passed:
error: type mismatch in f64.min, expected f64 but got i64.
+ error: type mismatch in f64.min, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:336: assert_invalid passed:
error: type mismatch in f64.mul, expected f64 but got i64.
+ error: type mismatch in f64.mul, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:337: assert_invalid passed:
error: type mismatch in f64.sub, expected f64 but got i64.
+ error: type mismatch in f64.sub, expected f64 but got f32.
error: @0x0000001f: on_binary_expr callback failed
out/third_party/testsuite/typecheck.wast:340: assert_invalid passed:
error: type mismatch in i32.eqz, expected i32 but got i64.
@@ -408,99 +453,131 @@ out/third_party/testsuite/typecheck.wast:361: assert_invalid passed:
error: @0x0000001a: on_unary_expr callback failed
out/third_party/testsuite/typecheck.wast:364: assert_invalid passed:
error: type mismatch in i32.eq, expected i32 but got i64.
+ error: type mismatch in i32.eq, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:365: assert_invalid passed:
error: type mismatch in i32.ge_s, expected i32 but got i64.
+ error: type mismatch in i32.ge_s, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:366: assert_invalid passed:
error: type mismatch in i32.ge_u, expected i32 but got i64.
+ error: type mismatch in i32.ge_u, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:367: assert_invalid passed:
error: type mismatch in i32.gt_s, expected i32 but got i64.
+ error: type mismatch in i32.gt_s, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:368: assert_invalid passed:
error: type mismatch in i32.gt_u, expected i32 but got i64.
+ error: type mismatch in i32.gt_u, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:369: assert_invalid passed:
error: type mismatch in i32.le_s, expected i32 but got i64.
+ error: type mismatch in i32.le_s, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:370: assert_invalid passed:
error: type mismatch in i32.le_u, expected i32 but got i64.
+ error: type mismatch in i32.le_u, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:371: assert_invalid passed:
error: type mismatch in i32.lt_s, expected i32 but got i64.
+ error: type mismatch in i32.lt_s, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:372: assert_invalid passed:
error: type mismatch in i32.lt_u, expected i32 but got i64.
+ error: type mismatch in i32.lt_u, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:373: assert_invalid passed:
error: type mismatch in i32.ne, expected i32 but got i64.
+ error: type mismatch in i32.ne, expected i32 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:374: assert_invalid passed:
error: type mismatch in i64.eq, expected i64 but got i32.
+ error: type mismatch in i64.eq, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:375: assert_invalid passed:
error: type mismatch in i64.ge_s, expected i64 but got i32.
+ error: type mismatch in i64.ge_s, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:376: assert_invalid passed:
error: type mismatch in i64.ge_u, expected i64 but got i32.
+ error: type mismatch in i64.ge_u, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:377: assert_invalid passed:
error: type mismatch in i64.gt_s, expected i64 but got i32.
+ error: type mismatch in i64.gt_s, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:378: assert_invalid passed:
error: type mismatch in i64.gt_u, expected i64 but got i32.
+ error: type mismatch in i64.gt_u, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:379: assert_invalid passed:
error: type mismatch in i64.le_s, expected i64 but got i32.
+ error: type mismatch in i64.le_s, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:380: assert_invalid passed:
error: type mismatch in i64.le_u, expected i64 but got i32.
+ error: type mismatch in i64.le_u, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:381: assert_invalid passed:
error: type mismatch in i64.lt_s, expected i64 but got i32.
+ error: type mismatch in i64.lt_s, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:382: assert_invalid passed:
error: type mismatch in i64.lt_u, expected i64 but got i32.
+ error: type mismatch in i64.lt_u, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:383: assert_invalid passed:
error: type mismatch in i64.ne, expected i64 but got i32.
+ error: type mismatch in i64.ne, expected i64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:384: assert_invalid passed:
error: type mismatch in f32.eq, expected f32 but got i64.
+ error: type mismatch in f32.eq, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:385: assert_invalid passed:
error: type mismatch in f32.ge, expected f32 but got i64.
+ error: type mismatch in f32.ge, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:386: assert_invalid passed:
error: type mismatch in f32.gt, expected f32 but got i64.
+ error: type mismatch in f32.gt, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:387: assert_invalid passed:
error: type mismatch in f32.le, expected f32 but got i64.
+ error: type mismatch in f32.le, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:388: assert_invalid passed:
error: type mismatch in f32.lt, expected f32 but got i64.
+ error: type mismatch in f32.lt, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:389: assert_invalid passed:
error: type mismatch in f32.ne, expected f32 but got i64.
+ error: type mismatch in f32.ne, expected f32 but got f64.
error: @0x00000023: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:390: assert_invalid passed:
error: type mismatch in f64.eq, expected f64 but got i64.
+ error: type mismatch in f64.eq, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:391: assert_invalid passed:
error: type mismatch in f64.ge, expected f64 but got i64.
+ error: type mismatch in f64.ge, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:392: assert_invalid passed:
error: type mismatch in f64.gt, expected f64 but got i64.
+ error: type mismatch in f64.gt, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:393: assert_invalid passed:
error: type mismatch in f64.le, expected f64 but got i64.
+ error: type mismatch in f64.le, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:394: assert_invalid passed:
error: type mismatch in f64.lt, expected f64 but got i64.
+ error: type mismatch in f64.lt, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:395: assert_invalid passed:
error: type mismatch in f64.ne, expected f64 but got i64.
+ error: type mismatch in f64.ne, expected f64 but got f32.
error: @0x0000001f: on_compare_expr callback failed
out/third_party/testsuite/typecheck.wast:398: assert_invalid passed:
error: type mismatch in i32.wrap/i64, expected i64 but got f32.
diff --git a/test/spec/unreached-invalid.txt b/test/spec/unreached-invalid.txt
new file mode 100644
index 00000000..99cf6a73
--- /dev/null
+++ b/test/spec/unreached-invalid.txt
@@ -0,0 +1,303 @@
+;;; TOOL: run-interp-spec
+;;; STDIN_FILE: third_party/testsuite/unreached-invalid.wast
+(;; STDOUT ;;;
+out/third_party/testsuite/unreached-invalid.wast:4: assert_invalid passed:
+ error: invalid local_index: 0 (max 0)
+ error: @0x0000001a: on_get_local_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:8: assert_invalid passed:
+ error: invalid global_index: 0 (max 0)
+ error: @0x0000001a: on_get_global_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:12: assert_invalid passed:
+ error: @0x0000001a: invalid call function index
+out/third_party/testsuite/unreached-invalid.wast:16: assert_invalid passed:
+ error: invalid depth: 1 (max 0)
+ error: @0x0000001a: on_br_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:21: assert_invalid passed:
+ error: type mismatch in i64.eqz, expected i64 but got i32.
+ error: @0x0000001b: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:27: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got i64.
+ error: @0x0000001f: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:33: assert_invalid passed:
+ error: type mismatch in select, expected i32 but got i64.
+ error: @0x00000023: on_select_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:42: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001b: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:46: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001a: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:50: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001c: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:56: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001a: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:60: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001c: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:64: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001e: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:71: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x0000001f: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:77: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x00000021: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:83: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000020: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:89: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000023: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:95: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x0000001e: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:101: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:107: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:113: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:119: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001c: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:125: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got f32.
+ error: @0x00000022: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:132: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x0000001c: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:138: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x0000001e: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:144: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x0000001d: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:150: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000020: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:156: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x0000001d: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:162: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: @0x00000025: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:168: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x0000001f: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:174: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000023: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:180: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001b: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:186: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got f32.
+ error: @0x00000021: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:193: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x0000001c: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:199: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x0000001e: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:205: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x0000001d: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:211: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000020: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:217: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x0000001d: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:223: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: @0x00000023: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:229: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x0000001f: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:235: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000021: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:241: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001b: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:247: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got f32.
+ error: @0x0000001f: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:254: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x0000001f: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:260: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x00000021: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:266: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000020: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:272: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000023: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:278: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:284: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000026: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:291: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x00000022: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:297: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:304: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001e: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:310: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got f32.
+ error: @0x00000022: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:318: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x00000020: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:324: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x00000022: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:330: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000021: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:336: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000024: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:342: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000021: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:348: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000027: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:354: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x00000023: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:360: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000025: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:366: assert_invalid passed:
+ error: type stack at end of function is 1, expected 0
+ error: @0x0000001f: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:372: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got f32.
+ error: @0x00000023: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:379: assert_invalid passed:
+ error: type stack size too small at i32.eqz. got 0, expected at least 1
+ error: @0x0000001d: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:385: assert_invalid passed:
+ error: type mismatch in i32.eqz, expected i32 but got f32.
+ error: @0x00000021: on_convert_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:391: assert_invalid passed:
+ error: type stack size too small at f32.eq. got 1, expected at least 2
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x0000001e: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:397: assert_invalid passed:
+ error: type mismatch in f32.eq, expected f32 but got i32.
+ error: @0x00000023: on_compare_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:403: assert_invalid passed:
+ error: type stack at end of if is 1, expected 0
+ error: @0x0000001e: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:409: assert_invalid passed:
+ error: type mismatch in if, expected i32 but got f32.
+ error: @0x00000022: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:415: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:421: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got f32.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:427: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:433: assert_invalid passed:
+ error: type mismatch in loop, expected i32 but got f32.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:440: assert_invalid passed:
+ error: type mismatch in return, expected i32 but got f64.
+ error: @0x00000025: on_return_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:447: assert_invalid passed:
+ error: type mismatch in br, expected i32 but got f64.
+ error: @0x00000029: on_br_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:454: assert_invalid passed:
+ error: type mismatch in br_if, expected i32 but got f32.
+ error: @0x00000021: on_br_if_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:460: assert_invalid passed:
+ error: type mismatch in br_table, expected i32 but got f32.
+ error: @0x00000022: on_br_table_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:467: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:473: assert_invalid passed:
+ error: type stack size too small at implicit return. got 0, expected at least 1
+ error: @0x00000020: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:479: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got i64.
+ error: @0x00000022: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:485: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000023: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:492: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000021: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:498: assert_invalid passed:
+ error: type stack size too small at block. got 0, expected at least 1
+ error: @0x00000022: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:504: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got i64.
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:511: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000023: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:517: assert_invalid passed:
+ error: type stack size too small at block. got 0, expected at least 1
+ error: @0x00000025: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:523: assert_invalid passed:
+ error: type mismatch in block, expected i32 but got i64.
+ error: @0x00000027: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:529: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000024: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:536: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:542: assert_invalid passed:
+ error: type stack size too small at implicit return. got 0, expected at least 1
+ error: @0x00000022: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:548: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got i64.
+ error: @0x00000024: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:554: assert_invalid passed:
+ error: type stack at end of block is 1, expected 0
+ error: @0x00000025: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:562: assert_invalid passed:
+ error: type stack at end of loop is 1, expected 0
+ error: @0x00000020: on_end_expr callback failed
+out/third_party/testsuite/unreached-invalid.wast:568: assert_invalid passed:
+ error: type stack size too small at implicit return. got 0, expected at least 1
+ error: @0x00000020: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:574: assert_invalid passed:
+ error: type mismatch in implicit return, expected i32 but got i64.
+ error: @0x00000022: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:581: assert_invalid passed:
+ error: type stack size too small at implicit return. got 0, expected at least 1
+ error: @0x0000001f: end_function_body callback failed
+out/third_party/testsuite/unreached-invalid.wast:587: assert_invalid passed:
+ error: type stack size too small at implicit return. got 0, expected at least 1
+ error: @0x00000020: end_function_body callback failed
+97/97 tests passed.
+;;; STDOUT ;;)
diff --git a/test/typecheck/bad-binary-type-mismatch-1.txt b/test/typecheck/bad-binary-type-mismatch-1.txt
index 5d142146..c52ae186 100644
--- a/test/typecheck/bad-binary-type-mismatch-1.txt
+++ b/test/typecheck/bad-binary-type-mismatch-1.txt
@@ -6,7 +6,7 @@
i32.add
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-binary-type-mismatch-1.txt:6:5: type mismatch at i32.add. got f32, expected i32
+out/test/typecheck/bad-binary-type-mismatch-1.txt:6:5: type mismatch in i32.add, expected i32 but got f32.
i32.add
^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-binary-type-mismatch-2.txt b/test/typecheck/bad-binary-type-mismatch-2.txt
index 2e92103e..6bd9b850 100644
--- a/test/typecheck/bad-binary-type-mismatch-2.txt
+++ b/test/typecheck/bad-binary-type-mismatch-2.txt
@@ -6,7 +6,7 @@
i32.add
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-binary-type-mismatch-2.txt:6:5: type mismatch at i32.add. got f32, expected i32
+out/test/typecheck/bad-binary-type-mismatch-2.txt:6:5: type mismatch in i32.add, expected i32 but got f32.
i32.add
^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-br-multi-type.txt b/test/typecheck/bad-br-multi-type.txt
deleted file mode 100644
index dd83e1c9..00000000
--- a/test/typecheck/bad-br-multi-type.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-;;; ERROR: 1
-(module
- (func (result f32)
- block $exit
- i32.const 1
- br 0
- f32.const 2
- end))
-(;; STDERR ;;;
-out/test/typecheck/bad-br-multi-type.txt:3:3: type stack size too small at function. got 0, expected at least 1
- (func (result f32)
- ^^^^^^
-out/test/typecheck/bad-br-multi-type.txt:3:3: type stack at end of function is 0. expected 1
- (func (result f32)
- ^^^^^^
-;;; STDERR ;;)
diff --git a/test/typecheck/bad-brtable-type-mismatch.txt b/test/typecheck/bad-brtable-type-mismatch.txt
index 433c6ad9..060aa146 100644
--- a/test/typecheck/bad-brtable-type-mismatch.txt
+++ b/test/typecheck/bad-brtable-type-mismatch.txt
@@ -11,7 +11,7 @@
end
i32.const 2))
(;; STDERR ;;;
-out/test/typecheck/bad-brtable-type-mismatch.txt:7:9: type mismatch at br_table key. got f32, expected i32
+out/test/typecheck/bad-brtable-type-mismatch.txt:7:9: type mismatch in br_table, expected i32 but got f32.
br_table 0 1
^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-call-type-mismatch.txt b/test/typecheck/bad-call-type-mismatch.txt
index 4ae136a4..49076145 100644
--- a/test/typecheck/bad-call-type-mismatch.txt
+++ b/test/typecheck/bad-call-type-mismatch.txt
@@ -5,7 +5,7 @@
i64.const 0
call 0))
(;; STDERR ;;;
-out/test/typecheck/bad-call-type-mismatch.txt:6:5: type mismatch for argument 0 of call. got i64, expected i32
+out/test/typecheck/bad-call-type-mismatch.txt:6:5: type mismatch in call, expected i32 but got i64.
call 0))
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-callimport-type-mismatch.txt b/test/typecheck/bad-callimport-type-mismatch.txt
index 75dfdd34..0f19ce1d 100644
--- a/test/typecheck/bad-callimport-type-mismatch.txt
+++ b/test/typecheck/bad-callimport-type-mismatch.txt
@@ -5,7 +5,7 @@
f32.const 0
call 0))
(;; STDERR ;;;
-out/test/typecheck/bad-callimport-type-mismatch.txt:6:5: type mismatch for argument 0 of call. got f32, expected i32
+out/test/typecheck/bad-callimport-type-mismatch.txt:6:5: type mismatch in call, expected i32 but got f32.
call 0))
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-callindirect-func-type-mismatch.txt b/test/typecheck/bad-callindirect-func-type-mismatch.txt
index 84f35a48..91a5e663 100644
--- a/test/typecheck/bad-callindirect-func-type-mismatch.txt
+++ b/test/typecheck/bad-callindirect-func-type-mismatch.txt
@@ -6,7 +6,7 @@
f32.const 0
call_indirect $t))
(;; STDERR ;;;
-out/test/typecheck/bad-callindirect-func-type-mismatch.txt:7:5: type mismatch at call_indirect function index. got f32, expected i32
+out/test/typecheck/bad-callindirect-func-type-mismatch.txt:7:5: type mismatch in call_indirect, expected i32 but got f32.
call_indirect $t))
^^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-callindirect-type-mismatch.txt b/test/typecheck/bad-callindirect-type-mismatch.txt
index 2e6896ef..1879bb82 100644
--- a/test/typecheck/bad-callindirect-type-mismatch.txt
+++ b/test/typecheck/bad-callindirect-type-mismatch.txt
@@ -9,7 +9,7 @@
call_indirect $t
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-callindirect-type-mismatch.txt:9:5: type mismatch for argument 0 of call_indirect. got f32, expected i32
+out/test/typecheck/bad-callindirect-type-mismatch.txt:9:5: type mismatch in call_indirect, expected i32 but got f32.
call_indirect $t
^^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-cast-type-mismatch.txt b/test/typecheck/bad-cast-type-mismatch.txt
index ac77b6b8..875af406 100644
--- a/test/typecheck/bad-cast-type-mismatch.txt
+++ b/test/typecheck/bad-cast-type-mismatch.txt
@@ -5,7 +5,7 @@
f32.reinterpret/i32
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-cast-type-mismatch.txt:5:5: type mismatch at f32.reinterpret/i32. got f32, expected i32
+out/test/typecheck/bad-cast-type-mismatch.txt:5:5: type mismatch in f32.reinterpret/i32, expected i32 but got f32.
f32.reinterpret/i32
^^^^^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-compare-type-mismatch-1.txt b/test/typecheck/bad-compare-type-mismatch-1.txt
index cd732985..c2720702 100644
--- a/test/typecheck/bad-compare-type-mismatch-1.txt
+++ b/test/typecheck/bad-compare-type-mismatch-1.txt
@@ -6,7 +6,7 @@
i32.eq
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-compare-type-mismatch-1.txt:6:5: type mismatch at i32.eq. got f32, expected i32
+out/test/typecheck/bad-compare-type-mismatch-1.txt:6:5: type mismatch in i32.eq, expected i32 but got f32.
i32.eq
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-compare-type-mismatch-2.txt b/test/typecheck/bad-compare-type-mismatch-2.txt
index 3c5e3990..d6e1e2c6 100644
--- a/test/typecheck/bad-compare-type-mismatch-2.txt
+++ b/test/typecheck/bad-compare-type-mismatch-2.txt
@@ -6,7 +6,7 @@
f32.lt
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-compare-type-mismatch-2.txt:6:5: type mismatch at f32.lt. got i32, expected f32
+out/test/typecheck/bad-compare-type-mismatch-2.txt:6:5: type mismatch in f32.lt, expected f32 but got i32.
f32.lt
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-convert-type-mismatch.txt b/test/typecheck/bad-convert-type-mismatch.txt
index 2f913ec3..d0a2b072 100644
--- a/test/typecheck/bad-convert-type-mismatch.txt
+++ b/test/typecheck/bad-convert-type-mismatch.txt
@@ -5,7 +5,7 @@
i32.trunc_s/f32
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-convert-type-mismatch.txt:5:5: type mismatch at i32.trunc_s/f32. got i32, expected f32
+out/test/typecheck/bad-convert-type-mismatch.txt:5:5: type mismatch in i32.trunc_s/f32, expected f32 but got i32.
i32.trunc_s/f32
^^^^^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-expr-if.txt b/test/typecheck/bad-expr-if.txt
index c3b81c1a..5156997b 100644
--- a/test/typecheck/bad-expr-if.txt
+++ b/test/typecheck/bad-expr-if.txt
@@ -12,7 +12,4 @@
out/test/typecheck/bad-expr-if.txt:10:5: type stack size too small at i32.add. got 1, expected at least 2
i32.add))
^^^^^^^
-out/test/typecheck/bad-expr-if.txt:3:3: type stack at end of function is 2. expected 1
- (func (result i32)
- ^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-function-result-type-mismatch.txt b/test/typecheck/bad-function-result-type-mismatch.txt
index b9f62622..b4d95838 100644
--- a/test/typecheck/bad-function-result-type-mismatch.txt
+++ b/test/typecheck/bad-function-result-type-mismatch.txt
@@ -3,7 +3,7 @@
(func (result i32)
f32.const 0))
(;; STDERR ;;;
-out/test/typecheck/bad-function-result-type-mismatch.txt:3:3: type mismatch at function. got f32, expected i32
- (func (result i32)
- ^^^^^^^^^^^^^^
+out/test/typecheck/bad-function-result-type-mismatch.txt:4:5: type mismatch in implicit return, expected i32 but got f32.
+ f32.const 0))
+ ^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-grow-memory-type-mismatch.txt b/test/typecheck/bad-grow-memory-type-mismatch.txt
index 42545188..932ac761 100644
--- a/test/typecheck/bad-grow-memory-type-mismatch.txt
+++ b/test/typecheck/bad-grow-memory-type-mismatch.txt
@@ -6,7 +6,7 @@
grow_memory
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-grow-memory-type-mismatch.txt:6:5: type mismatch at grow_memory. got f32, expected i32
+out/test/typecheck/bad-grow-memory-type-mismatch.txt:6:5: type mismatch in grow_memory, expected i32 but got f32.
grow_memory
^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-if-condition-type-mismatch.txt b/test/typecheck/bad-if-condition-type-mismatch.txt
index adbc3786..14eae4b4 100644
--- a/test/typecheck/bad-if-condition-type-mismatch.txt
+++ b/test/typecheck/bad-if-condition-type-mismatch.txt
@@ -2,20 +2,15 @@
(module
(func
f32.const 0
- if
+ if i32
i32.const 0
else
i32.const 0
- end)
+ end
+ drop)
)
(;; STDERR ;;;
-out/test/typecheck/bad-if-condition-type-mismatch.txt:5:5: type mismatch at if condition. got f32, expected i32
- if
- ^^^
-out/test/typecheck/bad-if-condition-type-mismatch.txt:5:5: type stack at end of if true branch is 1. expected 0
- if
- ^^^
-out/test/typecheck/bad-if-condition-type-mismatch.txt:5:5: type stack at end of if false branch is 1. expected 0
- if
+out/test/typecheck/bad-if-condition-type-mismatch.txt:5:5: type mismatch in if, expected i32 but got f32.
+ if i32
^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-if-type-mismatch.txt b/test/typecheck/bad-if-type-mismatch.txt
index 7335e1e4..e35bcd21 100644
--- a/test/typecheck/bad-if-type-mismatch.txt
+++ b/test/typecheck/bad-if-type-mismatch.txt
@@ -2,20 +2,14 @@
(module
(func
i32.const 0
- if
+ if i32
f32.const 0
else
i32.const 0
end
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-if-type-mismatch.txt:5:5: type stack at end of if true branch is 1. expected 0
- if
- ^^
-out/test/typecheck/bad-if-type-mismatch.txt:5:5: type stack at end of if false branch is 1. expected 0
- if
- ^^
-out/test/typecheck/bad-if-type-mismatch.txt:10:5: type stack size too small at drop. got 0, expected at least 1
- drop))
- ^^^^
+out/test/typecheck/bad-if-type-mismatch.txt:6:7: type mismatch in if true branch, expected i32 but got f32.
+ f32.const 0
+ ^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-if-value-void.txt b/test/typecheck/bad-if-value-void.txt
index fedcf453..e9b26c10 100644
--- a/test/typecheck/bad-if-value-void.txt
+++ b/test/typecheck/bad-if-value-void.txt
@@ -3,14 +3,15 @@
(func
block $b
i32.const 0
- if
- br $b
+ if f32
+ nop
else
f32.const 0
end
+ drop
end))
(;; STDERR ;;;
-out/test/typecheck/bad-if-value-void.txt:6:7: type stack at end of if false branch is 1. expected 0
- if
- ^^^
+out/test/typecheck/bad-if-value-void.txt:7:9: type stack size too small at if true branch. got 0, expected at least 1
+ nop
+ ^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-label-multi-type.txt b/test/typecheck/bad-label-multi-type.txt
deleted file mode 100644
index 95ea66b7..00000000
--- a/test/typecheck/bad-label-multi-type.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-;;; ERROR: 1
-(module
- (func (result i32)
- block $done
- i32.const 1
- if
- i32.const 2
- br $done
- end
- f32.const 3
- end))
-(;; STDERR ;;;
-out/test/typecheck/bad-label-multi-type.txt:4:5: type stack at end of block is 1. expected 0
- block $done
- ^^^
-out/test/typecheck/bad-label-multi-type.txt:3:3: type stack size too small at function. got 0, expected at least 1
- (func (result i32)
- ^^^^^^
-out/test/typecheck/bad-label-multi-type.txt:3:3: type stack at end of function is 0. expected 1
- (func (result i32)
- ^^^^^^
-;;; STDERR ;;)
diff --git a/test/typecheck/bad-load-type-mismatch.txt b/test/typecheck/bad-load-type-mismatch.txt
index ada73b6e..83fb33d0 100644
--- a/test/typecheck/bad-load-type-mismatch.txt
+++ b/test/typecheck/bad-load-type-mismatch.txt
@@ -6,7 +6,7 @@
i32.load
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-load-type-mismatch.txt:6:5: type mismatch at i32.load. got f32, expected i32
+out/test/typecheck/bad-load-type-mismatch.txt:6:5: type mismatch in i32.load, expected i32 but got f32.
i32.load
^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-nested-br.txt b/test/typecheck/bad-nested-br.txt
index f2304666..4a9cf64d 100644
--- a/test/typecheck/bad-nested-br.txt
+++ b/test/typecheck/bad-nested-br.txt
@@ -18,10 +18,7 @@
;; return statement here, or a value returned from (br $outer).
))
(;; STDERR ;;;
-out/test/typecheck/bad-nested-br.txt:3:3: type stack size too small at function. got 0, expected at least 1
- (func (result i32)
- ^
-out/test/typecheck/bad-nested-br.txt:3:3: type stack at end of function is 0. expected 1
- (func (result i32)
- ^
+out/test/typecheck/bad-nested-br.txt:15:7: type stack size too small at implicit return. got 0, expected at least 1
+ return
+ ^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-return-type-mismatch.txt b/test/typecheck/bad-return-type-mismatch.txt
index 2bdae27b..db6eaef7 100644
--- a/test/typecheck/bad-return-type-mismatch.txt
+++ b/test/typecheck/bad-return-type-mismatch.txt
@@ -4,7 +4,7 @@
f32.const 0
return))
(;; STDERR ;;;
-out/test/typecheck/bad-return-type-mismatch.txt:5:5: type mismatch at return. got f32, expected i32
+out/test/typecheck/bad-return-type-mismatch.txt:5:5: type mismatch in return, expected i32 but got f32.
return))
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-select-cond.txt b/test/typecheck/bad-select-cond.txt
index 07c8504d..fa2b1a19 100644
--- a/test/typecheck/bad-select-cond.txt
+++ b/test/typecheck/bad-select-cond.txt
@@ -6,7 +6,7 @@
f32.const 0
select))
(;; STDERR ;;;
-out/test/typecheck/bad-select-cond.txt:7:5: type mismatch at select. got f32, expected i32
+out/test/typecheck/bad-select-cond.txt:7:5: type mismatch in select, expected i32 but got f32.
select))
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-select-value0.txt b/test/typecheck/bad-select-value0.txt
index 6013276c..ebd63cac 100644
--- a/test/typecheck/bad-select-value0.txt
+++ b/test/typecheck/bad-select-value0.txt
@@ -6,7 +6,7 @@
i32.const 0
select))
(;; STDERR ;;;
-out/test/typecheck/bad-select-value0.txt:7:5: type mismatch at select. got f64, expected f32
+out/test/typecheck/bad-select-value0.txt:7:5: type mismatch in select, expected f32 but got f64.
select))
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-select-value1.txt b/test/typecheck/bad-select-value1.txt
index d998a1d4..a25546f2 100644
--- a/test/typecheck/bad-select-value1.txt
+++ b/test/typecheck/bad-select-value1.txt
@@ -7,7 +7,7 @@
select
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-select-value1.txt:7:5: type mismatch at select. got i64, expected f32
+out/test/typecheck/bad-select-value1.txt:7:5: type mismatch in select, expected f32 but got i64.
select
^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-setlocal-type-mismatch.txt b/test/typecheck/bad-setlocal-type-mismatch.txt
index 20bb3e86..57c8b7af 100644
--- a/test/typecheck/bad-setlocal-type-mismatch.txt
+++ b/test/typecheck/bad-setlocal-type-mismatch.txt
@@ -4,7 +4,7 @@
f32.const 0
set_local 0))
(;; STDERR ;;;
-out/test/typecheck/bad-setlocal-type-mismatch.txt:5:5: type mismatch at set_local. got f32, expected i32
+out/test/typecheck/bad-setlocal-type-mismatch.txt:5:5: type mismatch in set_local, expected i32 but got f32.
set_local 0))
^^^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-store-index-type-mismatch.txt b/test/typecheck/bad-store-index-type-mismatch.txt
index de9bb5de..4107703d 100644
--- a/test/typecheck/bad-store-index-type-mismatch.txt
+++ b/test/typecheck/bad-store-index-type-mismatch.txt
@@ -6,7 +6,7 @@
f32.const 0
i32.store))
(;; STDERR ;;;
-out/test/typecheck/bad-store-index-type-mismatch.txt:7:5: type mismatch at i32.store. got f32, expected i32
+out/test/typecheck/bad-store-index-type-mismatch.txt:7:5: type mismatch in i32.store, expected i32 but got f32.
i32.store))
^^^^^^^^^
;;; STDERR ;;)
diff --git a/test/typecheck/bad-unary-type-mismatch.txt b/test/typecheck/bad-unary-type-mismatch.txt
index 9c2e4e33..b7b3a49c 100644
--- a/test/typecheck/bad-unary-type-mismatch.txt
+++ b/test/typecheck/bad-unary-type-mismatch.txt
@@ -5,7 +5,7 @@
f32.neg
drop))
(;; STDERR ;;;
-out/test/typecheck/bad-unary-type-mismatch.txt:5:5: type mismatch at f32.neg. got f64, expected f32
+out/test/typecheck/bad-unary-type-mismatch.txt:5:5: type mismatch in f32.neg, expected f32 but got f64.
f32.neg
^^^^^^^
;;; STDERR ;;)
diff --git a/third_party/testsuite b/third_party/testsuite
-Subproject f5f64c51675f224fb3d603833636b378c562400
+Subproject eefbe96cf19dae516668ae24b8f470effda6f60