diff options
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 |