summaryrefslogtreecommitdiff
path: root/src/wasm-ast-checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-ast-checker.c')
-rw-r--r--src/wasm-ast-checker.c769
1 files changed, 441 insertions, 328 deletions
diff --git a/src/wasm-ast-checker.c b/src/wasm-ast-checker.c
index b940d621..2d0ca5b6 100644
--- a/src/wasm-ast-checker.c
+++ b/src/wasm-ast-checker.c
@@ -28,91 +28,71 @@
#include "wasm-binary-reader-ast.h"
#include "wasm-binary-reader.h"
-static const char* s_type_names[] = {
- "void", "i32", "i64", "f32", "f64",
-};
-WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_type_names) == WASM_NUM_TYPES);
-
-typedef enum TypeSet {
- WASM_TYPE_SET_VOID = 0,
- WASM_TYPE_SET_I32 = 1 << 0,
- WASM_TYPE_SET_I64 = 1 << 1,
- WASM_TYPE_SET_F32 = 1 << 2,
- WASM_TYPE_SET_F64 = 1 << 3,
- WASM_TYPE_SET_ALL = (1 << 4) - 1,
-} TypeSet;
-
-static const char* s_type_set_names[] = {
- "void",
- "i32",
- "i64",
- "i32 or i64",
- "f32",
- "i32 or f32",
- "i64 or f32",
- "i32, i64 or f32",
- "f64",
- "i32 or f64",
- "i64 or f64",
- "i32, i64 or f64",
- "f32 or f64",
- "i32, f32 or f64",
- "i64, f32 or f64",
- "i32, i64, f32 or f64",
-};
-WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_type_set_names) == WASM_TYPE_SET_ALL + 1);
-WASM_STATIC_ASSERT((1 << (WASM_TYPE_I32 - 1)) == WASM_TYPE_SET_I32);
-WASM_STATIC_ASSERT((1 << (WASM_TYPE_I64 - 1)) == WASM_TYPE_SET_I64);
-WASM_STATIC_ASSERT((1 << (WASM_TYPE_F32 - 1)) == WASM_TYPE_SET_F32);
-WASM_STATIC_ASSERT((1 << (WASM_TYPE_F64 - 1)) == WASM_TYPE_SET_F64);
-
-#define TYPE_TO_TYPE_SET(type) ((type) ? 1 << ((type)-1) : 0)
+typedef enum WasmCheckType {
+ WASM_CHECK_TYPE_VOID = WASM_TYPE_VOID,
+ WASM_CHECK_TYPE_I32 = WASM_TYPE_I32,
+ WASM_CHECK_TYPE_I64 = WASM_TYPE_I64,
+ WASM_CHECK_TYPE_F32 = WASM_TYPE_F32,
+ WASM_CHECK_TYPE_F64 = WASM_TYPE_F64,
+ WASM_CHECK_TYPE_ANY = WASM_NUM_TYPES,
+ WASM_NUM_CHECK_TYPES,
+ WASM_CHECK_TYPE____ = WASM_CHECK_TYPE_VOID, /* see table in wasm-common.h */
+} WasmCheckType;
+WASM_DEFINE_VECTOR(check_type, WasmCheckType);
+
+static const char* s_type_names[] = {"void", "i32", "i64", "f32", "f64", "any"};
+WASM_STATIC_ASSERT(WASM_ARRAY_SIZE(s_type_names) == WASM_NUM_CHECK_TYPES);
#define V(rtype, type1, type2, mem_size, code, NAME, text) \
- [code] = WASM_TYPE_##rtype,
-static WasmType s_opcode_rtype[] = {WASM_FOREACH_OPCODE(V)};
+ [code] = WASM_CHECK_TYPE_##rtype,
+static WasmCheckType s_opcode_rtype[] = {WASM_FOREACH_OPCODE(V)};
#undef V
#define V(rtype, type1, type2, mem_size, code, NAME, text) \
- [code] = WASM_TYPE_##type1,
-static WasmType s_opcode_type1[] = {WASM_FOREACH_OPCODE(V)};
+ [code] = WASM_CHECK_TYPE_##type1,
+static WasmCheckType s_opcode_type1[] = {WASM_FOREACH_OPCODE(V)};
#undef V
#define V(rtype, type1, type2, mem_size, code, NAME, text) \
- [code] = WASM_TYPE_##type2,
-static WasmType s_opcode_type2[] = {WASM_FOREACH_OPCODE(V)};
+ [code] = WASM_CHECK_TYPE_##type2,
+static WasmCheckType s_opcode_type2[] = {WASM_FOREACH_OPCODE(V)};
#undef V
-typedef enum CheckType {
- CHECK_TYPE_NAME,
- CHECK_TYPE_FULL,
-} CheckType;
+typedef size_t WasmSizeT;
+WASM_DEFINE_VECTOR(size_t, WasmSizeT);
+
+typedef enum CheckStyle {
+ CHECK_STYLE_NAME,
+ CHECK_STYLE_FULL,
+} CheckStyle;
typedef struct LabelNode {
const WasmLabel* label;
- WasmType expected_type;
+ WasmCheckType type;
const char* desc;
struct LabelNode* next;
} LabelNode;
typedef struct Context {
- CheckType check_type;
+ CheckStyle check_style;
WasmSourceErrorHandler* error_handler;
WasmAllocator* allocator;
WasmAstLexer* lexer;
const WasmModule* current_module;
const WasmFunc* current_func;
+ WasmSizeTVector type_stack_limit;
+ WasmCheckTypeVector type_stack;
LabelNode* top_label;
int max_depth;
WasmResult result;
} Context;
static void WASM_PRINTF_FORMAT(4, 5) print_error(Context* ctx,
- CheckType check_type,
+ CheckStyle check_style,
const WasmLocation* loc,
const char* fmt,
...) {
- if (check_type <= ctx->check_type) {
+ if (check_style <= ctx->check_style) {
ctx->result = WASM_ERROR;
va_list args;
va_start(args, fmt);
@@ -147,7 +127,7 @@ static void check_duplicate_bindings(Context* ctx,
WasmLocation* a_loc = &a->binding.loc;
WasmLocation* b_loc = &b->binding.loc;
WasmLocation* loc = a_loc->line > b_loc->line ? a_loc : b_loc;
- print_error(ctx, CHECK_TYPE_NAME, loc,
+ print_error(ctx, CHECK_STYLE_NAME, loc,
"redefinition of %s \"" PRIstringslice "\"", desc,
WASM_PRINTF_STRING_SLICE_ARG(a->binding.name));
}
@@ -169,11 +149,11 @@ static WasmResult check_var(Context* ctx,
return WASM_OK;
}
if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"undefined %s variable \"" PRIstringslice "\"", desc,
WASM_PRINTF_STRING_SLICE_ARG(var->name));
} else {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"%s variable out of range (max %d)", desc, max_index);
}
return WASM_ERROR;
@@ -226,7 +206,7 @@ static WasmResult check_func_type_var(Context* ctx,
static WasmResult check_local_var(Context* ctx,
const WasmVar* var,
- WasmType* out_type) {
+ WasmCheckType* out_type) {
const WasmModule* module = ctx->current_module;
const WasmFunc* func = ctx->current_func;
int max_index = wasm_get_num_params_and_locals(module, func);
@@ -244,11 +224,11 @@ static WasmResult check_local_var(Context* ctx,
}
if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"undefined local variable \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(var->name));
} else {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"local variable out of range (max %d)", max_index);
}
return WASM_ERROR;
@@ -258,68 +238,18 @@ static void check_align(Context* ctx,
const WasmLocation* loc,
uint32_t alignment) {
if (alignment != WASM_USE_NATURAL_ALIGNMENT && !is_power_of_two(alignment))
- print_error(ctx, CHECK_TYPE_FULL, loc, "alignment must be power-of-two");
+ print_error(ctx, CHECK_STYLE_FULL, loc, "alignment must be power-of-two");
}
static void check_offset(Context* ctx,
const WasmLocation* loc,
uint64_t offset) {
if (offset > UINT32_MAX) {
- print_error(ctx, CHECK_TYPE_FULL, loc,
+ print_error(ctx, CHECK_STYLE_FULL, loc,
"offset must be less than or equal to 0xffffffff");
}
}
-static void check_type(Context* ctx,
- const WasmLocation* loc,
- WasmType actual,
- WasmType expected,
- const char* desc) {
- if (expected != WASM_TYPE_VOID && actual != expected) {
- print_error(ctx, CHECK_TYPE_FULL, loc,
- "type mismatch%s. got %s, expected %s", desc,
- s_type_names[actual], s_type_names[expected]);
- }
-}
-
-static void check_type_set(Context* ctx,
- const WasmLocation* loc,
- WasmType actual,
- TypeSet expected,
- const char* desc) {
- if (expected != WASM_TYPE_SET_VOID &&
- (TYPE_TO_TYPE_SET(actual) & expected) == 0) {
- print_error(ctx, CHECK_TYPE_FULL, loc,
- "type mismatch%s. got %s, expected %s", desc,
- s_type_names[actual], s_type_set_names[expected]);
- }
-}
-
-static void check_type_exact(Context* ctx,
- const WasmLocation* loc,
- WasmType actual,
- WasmType expected,
- const char* desc) {
- if (actual != expected) {
- print_error(ctx, CHECK_TYPE_FULL, loc,
- "type mismatch%s. got %s, expected %s", desc,
- s_type_names[actual], s_type_names[expected]);
- }
-}
-
-static void check_type_arg_exact(Context* ctx,
- const WasmLocation* loc,
- WasmType actual,
- WasmType expected,
- const char* desc,
- int arg_index) {
- if (actual != expected) {
- print_error(ctx, CHECK_TYPE_FULL, loc,
- "type mismatch for argument %d of %s. got %s, expected %s",
- arg_index, desc, s_type_names[actual], s_type_names[expected]);
- }
-}
-
static LabelNode* find_label_by_name(LabelNode* top_label,
const WasmStringSlice* name) {
LabelNode* node = top_label;
@@ -356,11 +286,11 @@ static WasmResult check_label_var(Context* ctx,
}
if (var->type == WASM_VAR_TYPE_NAME) {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"undefined label variable \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(var->name));
} else {
- print_error(ctx, CHECK_TYPE_NAME, &var->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &var->loc,
"label variable out of range (max %d)", ctx->max_depth);
}
@@ -371,11 +301,11 @@ static void push_label(Context* ctx,
const WasmLocation* loc,
LabelNode* node,
const WasmLabel* label,
- WasmType expected_type,
+ WasmCheckType type,
const char* desc) {
node->label = label;
node->next = ctx->top_label;
- node->expected_type = expected_type;
+ node->type = type;
node->desc = desc;
ctx->top_label = node;
ctx->max_depth++;
@@ -386,131 +316,298 @@ static void pop_label(Context* ctx) {
ctx->top_label = ctx->top_label->next;
}
-static void check_expr(Context* ctx,
- const WasmExpr* expr,
- WasmType expected_type,
- const char* desc);
+static size_t type_stack_limit(Context* ctx) {
+ return ctx->type_stack_limit.data[ctx->type_stack_limit.size - 1];
+}
+
+static size_t push_type_stack_limit(Context* ctx) {
+ size_t limit = ctx->type_stack.size;
+ wasm_append_size_t_value(ctx->allocator, &ctx->type_stack_limit, &limit);
+ return limit;
+}
+
+static void pop_type_stack_limit(Context* ctx) {
+ assert(ctx->type_stack_limit.size > 0);
+ ctx->type_stack_limit.size--;
+}
+
+static void push_type(Context* ctx, WasmCheckType type) {
+ if (type != WASM_CHECK_TYPE_VOID)
+ wasm_append_check_type_value(ctx->allocator, &ctx->type_stack, &type);
+}
+
+static WasmCheckType 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 WASM_CHECK_TYPE_I32;
+ }
+ } else {
+ return WASM_CHECK_TYPE_VOID;
+ }
+}
+
+static WasmCheckType top_type(Context* ctx) {
+ return peek_type(ctx, 0, 1);
+}
+
+static WasmCheckType pop_type(Context* ctx) {
+ WasmCheckType 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 WasmLocation* loc,
+ WasmCheckType actual,
+ WasmCheckType expected,
+ const char* desc) {
+ if (actual != expected) {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch at %s. got %s, expected %s", desc,
+ s_type_names[actual], s_type_names[expected]);
+ }
+}
-static void check_expr_opt(Context* ctx,
+static void check_type_arg(Context* ctx,
const WasmLocation* loc,
- const WasmExpr* expr,
- WasmType expected_type,
- const char* desc) {
- if (expr)
- check_expr(ctx, expr, expected_type, desc);
- else
- check_type(ctx, loc, WASM_TYPE_VOID, expected_type, desc);
+ WasmCheckType actual,
+ WasmCheckType expected,
+ const char* desc,
+ int arg_index) {
+ if (actual != expected) {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch for argument %d of %s. got %s, expected %s",
+ arg_index, desc, s_type_names[actual], s_type_names[expected]);
+ }
+}
+
+static void check_assert_return_nan_type(Context* ctx,
+ const WasmLocation* loc,
+ WasmCheckType actual,
+ const char* desc) {
+ /* when using assert_return_nan, the result can be either a f32 or f64 type
+ * so we special case it here. */
+ if (actual != WASM_CHECK_TYPE_F32 && actual != WASM_CHECK_TYPE_F64) {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch at %s. got %s, expected f32 or f64", desc,
+ s_type_names[actual]);
+ }
+}
+
+static WasmCheckType join_type(Context* ctx,
+ const WasmLocation* loc,
+ WasmCheckType t1,
+ WasmCheckType t2,
+ const char* desc) {
+ if (t1 == WASM_CHECK_TYPE_ANY) {
+ return t2;
+ } else if (t2 == WASM_CHECK_TYPE_ANY) {
+ return t1;
+ } else if (t1 == t2) {
+ return t1;
+ } else {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch at %s. got %s, expected %s", desc,
+ s_type_names[t1], s_type_names[t2]);
+ return t1;
+ }
+}
+
+static void unify_label_type(Context* ctx,
+ const WasmLocation* loc,
+ LabelNode* node,
+ WasmCheckType type,
+ const char* desc) {
+ if (node->type == WASM_CHECK_TYPE_ANY) {
+ node->type = type;
+ } else if (type != WASM_CHECK_TYPE_ANY && node->type != type) {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch at %s. got %s, expected %s", desc,
+ s_type_names[type], s_type_names[node->type]);
+ }
+}
+
+static void transform_stack(Context* ctx,
+ const WasmLocation* loc,
+ const char* desc,
+ size_t before_size,
+ size_t after_size,
+ ...) {
+ size_t i;
+ va_list args;
+ va_start(args, after_size);
+ size_t limit = type_stack_limit(ctx);
+ size_t avail = ctx->type_stack.size - limit;
+ if (before_size <= avail) {
+ for (i = 0; i < before_size; ++i) {
+ WasmCheckType actual =
+ ctx->type_stack.data[ctx->type_stack.size - before_size + i];
+ WasmCheckType expected = va_arg(args, WasmCheckType);
+ /* TODO(binji): could give a better location for the error by storing the
+ * location in the type stack; i.e. where this type was added to the
+ * stack */
+ check_type(ctx, loc, actual, expected, desc);
+ }
+ ctx->type_stack.size -= before_size;
+ } else {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type stack size too small at %s. got %" PRIzd
+ ", expected at least %" PRIzd,
+ desc, avail, before_size);
+ ctx->type_stack.size = limit;
+ }
+ assert(after_size <= 1);
+ if (after_size > 0)
+ push_type(ctx, va_arg(args, WasmCheckType));
+ va_end(args);
}
static void check_br(Context* ctx,
const WasmLocation* loc,
const WasmVar* var,
- const WasmExpr* expr,
+ WasmCheckType type,
const char* desc) {
LabelNode* node;
- if (WASM_FAILED(check_label_var(ctx, ctx->top_label, var, &node)))
- return;
-
- check_expr_opt(ctx, loc, expr, node->expected_type, desc);
+ if (WASM_SUCCEEDED(check_label_var(ctx, ctx->top_label, var, &node))) {
+ unify_label_type(ctx, loc, node, type, desc);
+ }
}
static void check_call(Context* ctx,
const WasmLocation* loc,
const WasmStringSlice* callee_name,
const WasmFuncSignature* sig,
- const WasmExpr* first_arg,
- size_t num_args,
- WasmType expected_type,
const char* desc) {
size_t expected_args = sig->param_types.size;
- if (expected_args == num_args) {
- char buffer[100];
- wasm_snprintf(buffer, 100, " of %s result", desc);
- check_type(ctx, loc, sig->result_type, expected_type, buffer);
- const WasmExpr* arg;
+ size_t limit = type_stack_limit(ctx);
+ size_t avail = ctx->type_stack.size - limit;
+ if (expected_args <= avail) {
size_t i;
- for (i = 0, arg = first_arg; i < num_args; ++i, arg = arg->next) {
- wasm_snprintf(buffer, 100, " of argument %" PRIzd " of %s", i, desc);
- check_expr(ctx, arg, sig->param_types.data[i], buffer);
+ for (i = 0; i < sig->param_types.size; ++i) {
+ WasmCheckType actual =
+ ctx->type_stack.data[ctx->type_stack.size - expected_args + i];
+ WasmCheckType expected = sig->param_types.data[i];
+ check_type_arg(ctx, loc, actual, expected, desc, i);
}
+ ctx->type_stack.size -= expected_args;
} else {
- char* callee_name_str = "";
- if (callee_name && callee_name->start) {
- size_t length = callee_name->length + 10;
- callee_name_str = alloca(length);
- wasm_snprintf(callee_name_str, length, " \"" PRIstringslice "\"",
- WASM_PRINTF_STRING_SLICE_ARG(*callee_name));
- }
- print_error(ctx, CHECK_TYPE_FULL, loc,
- "too %s parameters to function%s in %s. got %" PRIzd
- ", expected %" PRIzd,
- num_args > expected_args ? "many" : "few", callee_name_str,
- desc, num_args, expected_args);
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "type stack size too small at %s. got %" PRIzd
+ ", expected at least %" PRIzd,
+ desc, avail, expected_args);
+ ctx->type_stack.size = limit;
}
+ push_type(ctx, sig->result_type);
}
-static void check_expr_list(Context* ctx,
- const WasmLocation* loc,
- const WasmExpr* first,
- WasmType expected_type,
- const char* desc) {
+static void check_expr(Context* ctx, const WasmExpr* expr);
+
+static WasmCheckType check_block(Context* ctx,
+ const WasmLocation* loc,
+ const WasmExpr* first,
+ const char* desc) {
if (first) {
+ size_t limit = push_type_stack_limit(ctx);
const WasmExpr* expr;
for (expr = first; expr; expr = expr->next) {
- if (expr->next)
- check_expr(ctx, expr, WASM_TYPE_VOID, "");
- else
- check_expr(ctx, expr, expected_type, desc);
+ check_expr(ctx, expr);
+ /* stop typechecking if we hit unreachable code */
+ if (top_type(ctx) == WASM_CHECK_TYPE_ANY)
+ break;
}
+ WasmCheckType result = top_type(ctx);
+ if (result != WASM_CHECK_TYPE_ANY) {
+ size_t result_arity = ctx->type_stack.size - limit;
+ if (result_arity > 1) {
+ print_error(ctx, CHECK_STYLE_FULL, loc,
+ "maximum arity for %s is 1, got %" PRIzd, desc,
+ result_arity);
+ } else if (result_arity == 0) {
+ result = WASM_CHECK_TYPE_VOID;
+ }
+ }
+ ctx->type_stack.size = limit;
+ pop_type_stack_limit(ctx);
+ return result;
} else {
- check_type(ctx, loc, WASM_TYPE_VOID, expected_type, desc);
+ return WASM_CHECK_TYPE_VOID;
}
}
-static void check_expr(Context* ctx,
- const WasmExpr* expr,
- WasmType expected_type,
- const char* desc) {
+static void check_expr(Context* ctx, const WasmExpr* expr) {
switch (expr->type) {
case WASM_EXPR_TYPE_BINARY: {
- WasmType rtype = s_opcode_rtype[expr->binary.opcode];
- WasmType type1 = s_opcode_type1[expr->binary.opcode];
- WasmType type2 = s_opcode_type2[expr->binary.opcode];
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->binary.left, type1, " of argument 0 of binary op");
- check_expr(ctx, expr->binary.right, type2, " of argument 1 of binary op");
+ WasmCheckType rtype = s_opcode_rtype[expr->binary.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->binary.opcode];
+ WasmCheckType type2 = s_opcode_type2[expr->binary.opcode];
+ transform_stack(ctx, &expr->loc, "binary", 2, 1, type1, type2, rtype);
break;
}
case WASM_EXPR_TYPE_BLOCK: {
LabelNode node;
- push_label(ctx, &expr->loc, &node, &expr->block.label, expected_type,
- "block");
- check_expr_list(ctx, &expr->loc, expr->block.first, expected_type,
- " of block");
+ push_label(ctx, &expr->loc, &node, &expr->block.label,
+ WASM_CHECK_TYPE_ANY, "block");
+ WasmCheckType rtype =
+ check_block(ctx, &expr->loc, expr->block.first, "block");
+ rtype = join_type(ctx, &expr->loc, node.type, rtype, "block");
pop_label(ctx);
+ push_type(ctx, rtype);
break;
}
case WASM_EXPR_TYPE_BR: {
- check_br(ctx, &expr->loc, &expr->br.var, expr->br.expr, " of br value");
+ WasmCheckType type = peek_type(ctx, 0, expr->br.arity);
+ check_br(ctx, &expr->loc, &expr->br.var, type, "br value");
+ if (expr->br.arity > 0) {
+ transform_stack(ctx, &expr->loc, "br", 1, 1, type, WASM_CHECK_TYPE_ANY);
+ } else {
+ transform_stack(ctx, &expr->loc, "br", 0, 1, WASM_CHECK_TYPE_ANY);
+ }
break;
}
case WASM_EXPR_TYPE_BR_IF: {
- check_type(ctx, &expr->loc, WASM_TYPE_VOID, expected_type, desc);
- check_br(ctx, &expr->loc, &expr->br_if.var, expr->br_if.expr,
- " of br_if value");
- check_expr(ctx, expr->br_if.cond, WASM_TYPE_I32, " of br_if condition");
+ WasmCheckType type = peek_type(ctx, 1, expr->br_if.arity);
+ check_br(ctx, &expr->loc, &expr->br_if.var, type, "br_if value");
+ if (expr->br_if.arity > 0) {
+ transform_stack(ctx, &expr->loc, "br_if", 2, 1, type,
+ WASM_CHECK_TYPE_I32, WASM_CHECK_TYPE_VOID);
+ } else {
+ transform_stack(ctx, &expr->loc, "br_if", 1, 1, WASM_CHECK_TYPE_I32,
+ WASM_CHECK_TYPE_VOID);
+ }
+ break;
+ }
+
+ case WASM_EXPR_TYPE_BR_TABLE: {
+ WasmCheckType type = peek_type(ctx, 1, expr->br_table.arity);
+ size_t i;
+ for (i = 0; i < expr->br_table.targets.size; ++i) {
+ check_br(ctx, &expr->loc, &expr->br_table.targets.data[i], type,
+ "br_table target");
+ }
+ check_br(ctx, &expr->loc, &expr->br_table.default_target, type,
+ "br_table default target");
+ if (expr->br_table.arity > 0) {
+ transform_stack(ctx, &expr->loc, "br_table", 2, 1, type,
+ WASM_CHECK_TYPE_I32, WASM_CHECK_TYPE_ANY);
+ } else {
+ transform_stack(ctx, &expr->loc, "br_table", 1, 1, WASM_CHECK_TYPE_I32,
+ WASM_CHECK_TYPE_ANY);
+ }
break;
}
case WASM_EXPR_TYPE_CALL: {
const WasmFunc* callee;
if (WASM_SUCCEEDED(check_func_var(ctx, &expr->call.var, &callee))) {
- check_call(ctx, &expr->loc, &callee->name, &callee->decl.sig,
- expr->call.first_arg, expr->call.num_args, expected_type,
- "call");
+ check_call(ctx, &expr->loc, &callee->name, &callee->decl.sig, "call");
}
break;
}
@@ -519,182 +616,172 @@ static void check_expr(Context* ctx,
const WasmImport* import;
if (WASM_SUCCEEDED(check_import_var(ctx, &expr->call.var, &import))) {
check_call(ctx, &expr->loc, &import->name, &import->decl.sig,
- expr->call.first_arg, expr->call.num_args, expected_type,
"call_import");
}
break;
}
case WASM_EXPR_TYPE_CALL_INDIRECT: {
- check_expr(ctx, expr->call_indirect.expr, WASM_TYPE_I32,
- " of function index");
const WasmFuncType* func_type;
if (WASM_SUCCEEDED(
- check_func_type_var(ctx, &expr->call_indirect.var, &func_type))) {
- check_call(ctx, &expr->loc, NULL, &func_type->sig,
- expr->call_indirect.first_arg, expr->call_indirect.num_args,
- expected_type, "call_indirect");
+ check_func_type_var(ctx, &expr->call.var, &func_type))) {
+ WasmCheckType type = pop_type(ctx);
+ check_type(ctx, &expr->loc, type, WASM_CHECK_TYPE_I32,
+ "function index");
+ check_call(ctx, &expr->loc, NULL, &func_type->sig, "call_indirect");
}
break;
}
case WASM_EXPR_TYPE_COMPARE: {
- WasmType rtype = s_opcode_rtype[expr->compare.opcode];
- WasmType type1 = s_opcode_type1[expr->compare.opcode];
- WasmType type2 = s_opcode_type2[expr->compare.opcode];
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->compare.left, type1,
- " of argument 0 of compare op");
- check_expr(ctx, expr->compare.right, type2,
- " of argument 1 of compare op");
+ WasmCheckType rtype = s_opcode_rtype[expr->compare.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->compare.opcode];
+ WasmCheckType type2 = s_opcode_type2[expr->compare.opcode];
+ transform_stack(ctx, &expr->loc, "compare", 2, 1, type1, type2, rtype);
break;
}
case WASM_EXPR_TYPE_CONST:
- check_type(ctx, &expr->loc, expr->const_.type, expected_type, desc);
+ push_type(ctx, expr->const_.type);
break;
case WASM_EXPR_TYPE_CONVERT: {
- WasmType rtype = s_opcode_rtype[expr->convert.opcode];
- WasmType type1 = s_opcode_type1[expr->convert.opcode];
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->convert.expr, type1, " of convert op");
+ WasmCheckType rtype = s_opcode_rtype[expr->convert.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->convert.opcode];
+ transform_stack(ctx, &expr->loc, "convert", 1, 1, type1, rtype);
+ break;
+ }
+
+ case WASM_EXPR_TYPE_DROP: {
+ WasmType type = top_type(ctx);
+ transform_stack(ctx, &expr->loc, "drop", 1, 0, type);
break;
}
case WASM_EXPR_TYPE_GET_LOCAL: {
- WasmType type;
+ WasmCheckType type;
if (WASM_SUCCEEDED(check_local_var(ctx, &expr->get_local.var, &type))) {
- check_type(ctx, &expr->loc, type, expected_type, desc);
+ push_type(ctx, type);
}
break;
}
case WASM_EXPR_TYPE_GROW_MEMORY:
- check_type(ctx, &expr->loc, WASM_TYPE_I32, expected_type,
- " in grow_memory");
- check_expr(ctx, expr->grow_memory.expr, WASM_TYPE_I32, " of grow_memory");
+ transform_stack(ctx, &expr->loc, "grow_memory", 1, 1, WASM_CHECK_TYPE_I32,
+ WASM_CHECK_TYPE_I32);
break;
case WASM_EXPR_TYPE_IF: {
LabelNode node;
- check_expr(ctx, expr->if_.cond, WASM_TYPE_I32, " of condition");
- push_label(ctx, &expr->loc, &node, &expr->if_.true_.label, expected_type,
- "if branch");
- check_expr_list(ctx, &expr->loc, expr->if_.true_.first, expected_type,
- " of if branch");
+ push_label(ctx, &expr->loc, &node, &expr->if_.true_.label,
+ WASM_CHECK_TYPE_ANY, "if branch");
+ WasmCheckType rtype =
+ check_block(ctx, &expr->loc, expr->if_.true_.first, "if expression");
+ rtype = join_type(ctx, &expr->loc, rtype, WASM_CHECK_TYPE_VOID,
+ "if expression");
pop_label(ctx);
- check_type(ctx, &expr->loc, WASM_TYPE_VOID, expected_type, desc);
+ transform_stack(ctx, &expr->loc, "if expression", 1, 1,
+ WASM_CHECK_TYPE_I32, rtype);
break;
}
case WASM_EXPR_TYPE_IF_ELSE: {
LabelNode node;
- check_expr(ctx, expr->if_else.cond, WASM_TYPE_I32, " of condition");
push_label(ctx, &expr->loc, &node, &expr->if_else.true_.label,
- expected_type, "if true branch");
- check_expr_list(ctx, &expr->loc, expr->if_else.true_.first, expected_type,
- " of if branch");
+ WASM_CHECK_TYPE_ANY, "if true branch");
+ WasmCheckType rtype1 = check_block(
+ ctx, &expr->loc, expr->if_else.true_.first, "if true branch");
pop_label(ctx);
push_label(ctx, &expr->loc, &node, &expr->if_else.false_.label,
- expected_type, "if false branch");
- check_expr_list(ctx, &expr->loc, expr->if_else.false_.first,
- expected_type, " of if branch");
+ WASM_CHECK_TYPE_ANY, "if false branch");
+ WasmCheckType rtype2 = check_block(
+ ctx, &expr->loc, expr->if_else.false_.first, "if false branch");
pop_label(ctx);
+ WasmCheckType rtype =
+ join_type(ctx, &expr->loc, rtype1, rtype2, "of if expression");
+ transform_stack(ctx, &expr->loc, "if expression", 1, 1,
+ WASM_CHECK_TYPE_I32, rtype);
break;
}
case WASM_EXPR_TYPE_LOAD: {
- WasmType rtype = s_opcode_rtype[expr->load.opcode];
- WasmType type1 = s_opcode_type1[expr->load.opcode];
+ WasmCheckType rtype = s_opcode_rtype[expr->load.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->load.opcode];
check_align(ctx, &expr->loc, expr->load.align);
check_offset(ctx, &expr->loc, expr->load.offset);
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->load.addr, type1, " of load index");
+ transform_stack(ctx, &expr->loc, "load", 1, 1, type1, rtype);
break;
}
case WASM_EXPR_TYPE_LOOP: {
- LabelNode outer_node;
- LabelNode inner_node;
- push_label(ctx, &expr->loc, &outer_node, &expr->loop.outer, expected_type,
- "loop outer label");
- push_label(ctx, &expr->loc, &inner_node, &expr->loop.inner,
- WASM_TYPE_VOID, "loop inner label");
- check_expr_list(ctx, &expr->loc, expr->loop.first, expected_type,
- " of loop");
- pop_label(ctx);
+ LabelNode node;
+ push_label(ctx, &expr->loc, &node, &expr->loop.label,
+ WASM_CHECK_TYPE_VOID, "loop label");
+ WasmCheckType rtype =
+ check_block(ctx, &expr->loc, expr->loop.first, "loop");
pop_label(ctx);
+ push_type(ctx, rtype);
break;
}
case WASM_EXPR_TYPE_CURRENT_MEMORY:
- check_type(ctx, &expr->loc, WASM_TYPE_I32, expected_type,
- " in current_memory");
+ push_type(ctx, WASM_CHECK_TYPE_I32);
break;
case WASM_EXPR_TYPE_NOP:
- check_type(ctx, &expr->loc, WASM_TYPE_VOID, expected_type, " in nop");
break;
case WASM_EXPR_TYPE_RETURN: {
- WasmType result_type =
+ WasmCheckType result_type =
wasm_get_result_type(ctx->current_module, ctx->current_func);
- check_expr_opt(ctx, &expr->loc, expr->return_.expr, result_type,
- " of return");
+ if (result_type != WASM_TYPE_VOID) {
+ transform_stack(ctx, &expr->loc, "return", 1, 1, result_type,
+ WASM_CHECK_TYPE_ANY);
+ } else {
+ transform_stack(ctx, &expr->loc, "return", 0, 1, WASM_CHECK_TYPE_ANY);
+ }
break;
}
- case WASM_EXPR_TYPE_SELECT:
- check_expr(ctx, expr->select.cond, WASM_TYPE_I32, " of condition");
- check_expr(ctx, expr->select.true_, expected_type,
- " of argument 0 of select op");
- check_expr(ctx, expr->select.false_, expected_type,
- " of argment 1 of select op");
+ case WASM_EXPR_TYPE_SELECT: {
+ WasmCheckType type = peek_type(ctx, 1, 1);
+ transform_stack(ctx, &expr->loc, "select", 3, 1, type, type,
+ WASM_CHECK_TYPE_I32, type);
break;
+ }
case WASM_EXPR_TYPE_SET_LOCAL: {
- WasmType type;
- if (WASM_SUCCEEDED(check_local_var(ctx, &expr->set_local.var, &type))) {
- check_type(ctx, &expr->loc, type, expected_type, desc);
- check_expr(ctx, expr->set_local.expr, type, " of set_local");
- }
+ WasmCheckType type = WASM_TYPE_I32;
+ check_local_var(ctx, &expr->set_local.var, &type);
+ transform_stack(ctx, &expr->loc, "set_local", 1, 0, type);
break;
}
case WASM_EXPR_TYPE_STORE: {
- WasmType rtype = s_opcode_rtype[expr->store.opcode];
- WasmType type1 = s_opcode_type1[expr->store.opcode];
- WasmType type2 = s_opcode_type2[expr->store.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->store.opcode];
+ WasmCheckType type2 = s_opcode_type2[expr->store.opcode];
check_align(ctx, &expr->loc, expr->store.align);
check_offset(ctx, &expr->loc, expr->store.offset);
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->store.addr, type1, " of store index");
- check_expr(ctx, expr->store.value, type2, " of store value");
+ transform_stack(ctx, &expr->loc, "store", 2, 0, type1, type2);
break;
}
- case WASM_EXPR_TYPE_BR_TABLE: {
- check_expr(ctx, expr->br_table.key, WASM_TYPE_I32, " of key");
- size_t i;
- for (i = 0; i < expr->br_table.targets.size; ++i) {
- check_br(ctx, &expr->loc, &expr->br_table.targets.data[i],
- expr->br_table.expr, " of br_table target");
- }
- check_br(ctx, &expr->loc, &expr->br_table.default_target,
- expr->br_table.expr, " of br_table default target");
+ case WASM_EXPR_TYPE_TEE_LOCAL: {
+ WasmCheckType type = WASM_TYPE_I32;
+ check_local_var(ctx, &expr->tee_local.var, &type);
+ transform_stack(ctx, &expr->loc, "tee_local", 1, 1, type, type);
break;
}
case WASM_EXPR_TYPE_UNARY: {
- WasmType rtype = s_opcode_rtype[expr->unary.opcode];
- WasmType type1 = s_opcode_type1[expr->unary.opcode];
- check_type(ctx, &expr->loc, rtype, expected_type, desc);
- check_expr(ctx, expr->unary.expr, type1, " of unary op");
+ WasmCheckType rtype = s_opcode_rtype[expr->unary.opcode];
+ WasmCheckType type1 = s_opcode_type1[expr->unary.opcode];
+ transform_stack(ctx, &expr->loc, "unary", 1, 1, type1, rtype);
break;
}
case WASM_EXPR_TYPE_UNREACHABLE:
+ push_type(ctx, WASM_CHECK_TYPE_ANY);
break;
}
}
@@ -705,18 +792,25 @@ static void check_func_signature_matches_func_type(
const WasmFuncSignature* sig,
const WasmFuncType* func_type) {
size_t num_params = sig->param_types.size;
- check_type_exact(ctx, loc, sig->result_type,
- wasm_get_func_type_result_type(func_type),
- " between function result and function type result");
+ /* special case this check to give a better error message */
+ WasmCheckType func_type_result_type =
+ wasm_get_func_type_result_type(func_type);
+ if (sig->result_type != func_type_result_type) {
+ print_error(
+ ctx, CHECK_STYLE_FULL, loc,
+ "type mismatch between function result type (%s) and function type "
+ "result type (%s)\n",
+ s_type_names[sig->result_type], s_type_names[func_type_result_type]);
+ }
if (num_params == wasm_get_func_type_num_params(func_type)) {
size_t i;
for (i = 0; i < num_params; ++i) {
- check_type_arg_exact(ctx, loc, sig->param_types.data[i],
- wasm_get_func_type_param_type(func_type, i),
- "function", i);
+ check_type_arg(ctx, loc, sig->param_types.data[i],
+ wasm_get_func_type_param_type(func_type, i), "function",
+ i);
}
} else {
- print_error(ctx, CHECK_TYPE_FULL, loc,
+ print_error(ctx, CHECK_STYLE_FULL, loc,
"expected %" PRIzd " parameters, got %" PRIzd,
wasm_get_func_type_num_params(func_type), num_params);
}
@@ -743,8 +837,10 @@ static void check_func(Context* ctx,
WasmLabel label = wasm_empty_string_slice();
push_label(ctx, &func->loc, &node, &label, func->decl.sig.result_type,
"func");
- check_expr_list(ctx, &func->loc, func->first_expr, func->decl.sig.result_type,
- " of function result");
+ WasmCheckType rtype =
+ check_block(ctx, &func->loc, func->first_expr, "function result");
+ join_type(ctx, &func->loc, rtype, func->decl.sig.result_type,
+ "function result");
pop_label(ctx);
ctx->current_func = NULL;
}
@@ -768,19 +864,19 @@ static void check_table(Context* ctx, const WasmVarVector* table) {
static void check_memory(Context* ctx, const WasmMemory* memory) {
if (memory->initial_pages > WASM_MAX_PAGES) {
- print_error(ctx, CHECK_TYPE_FULL, &memory->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &memory->loc,
"initial pages (%" PRIu64 ") must be <= (%u)",
memory->initial_pages, WASM_MAX_PAGES);
}
if (memory->max_pages > WASM_MAX_PAGES) {
- print_error(ctx, CHECK_TYPE_FULL, &memory->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &memory->loc,
"max pages (%" PRIu64 ") must be <= (%u)", memory->max_pages,
WASM_MAX_PAGES);
}
if (memory->max_pages < memory->initial_pages) {
- print_error(ctx, CHECK_TYPE_FULL, &memory->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &memory->loc,
"max pages (%" PRIu64 ") must be >= initial pages (%" PRIu64
")",
memory->max_pages, memory->initial_pages);
@@ -791,17 +887,17 @@ static void check_memory(Context* ctx, const WasmMemory* memory) {
for (i = 0; i < memory->segments.size; ++i) {
const WasmSegment* segment = &memory->segments.data[i];
if (segment->addr < last_end) {
- print_error(ctx, CHECK_TYPE_FULL, &segment->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &segment->loc,
"address (%u) less than end of previous segment (%u)",
segment->addr, last_end);
}
if (segment->addr > memory->initial_pages * WASM_PAGE_SIZE) {
- print_error(ctx, CHECK_TYPE_FULL, &segment->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &segment->loc,
"address (%u) greater than initial memory size (%" PRIu64 ")",
segment->addr, memory->initial_pages * WASM_PAGE_SIZE);
} else if (segment->addr + segment->size >
memory->initial_pages * WASM_PAGE_SIZE) {
- print_error(ctx, CHECK_TYPE_FULL, &segment->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &segment->loc,
"segment ends past the end of initial memory size (%" PRIu64
")",
memory->initial_pages * WASM_PAGE_SIZE);
@@ -841,7 +937,7 @@ static void check_module(Context* ctx, const WasmModule* module) {
case WASM_MODULE_FIELD_TYPE_TABLE:
if (seen_table) {
- print_error(ctx, CHECK_TYPE_FULL, &field->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"only one table allowed");
}
check_table(ctx, &field->table);
@@ -850,7 +946,7 @@ static void check_module(Context* ctx, const WasmModule* module) {
case WASM_MODULE_FIELD_TYPE_MEMORY:
if (seen_memory) {
- print_error(ctx, CHECK_TYPE_FULL, &field->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"only one memory block allowed");
}
check_memory(ctx, &field->memory);
@@ -862,7 +958,7 @@ static void check_module(Context* ctx, const WasmModule* module) {
case WASM_MODULE_FIELD_TYPE_START: {
if (seen_start) {
- print_error(ctx, CHECK_TYPE_FULL, &field->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"only one start function allowed");
}
@@ -870,13 +966,13 @@ static void check_module(Context* ctx, const WasmModule* module) {
check_func_var(ctx, &field->start, &start_func);
if (start_func) {
if (wasm_get_num_params(ctx->current_module, start_func) != 0) {
- print_error(ctx, CHECK_TYPE_FULL, &field->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"start function must be nullary");
}
if (wasm_get_result_type(ctx->current_module, start_func) !=
WASM_TYPE_VOID) {
- print_error(ctx, CHECK_TYPE_FULL, &field->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &field->loc,
"start function must not return anything");
}
}
@@ -887,7 +983,8 @@ static void check_module(Context* ctx, const WasmModule* module) {
}
if (seen_export_memory && !seen_memory) {
- print_error(ctx, CHECK_TYPE_FULL, export_memory_loc, "no memory to export");
+ print_error(ctx, CHECK_STYLE_FULL, export_memory_loc,
+ "no memory to export");
}
check_duplicate_bindings(ctx, &module->func_bindings, "function");
@@ -906,10 +1003,10 @@ static void on_read_binary_error(uint32_t offset,
void* user_data) {
BinaryErrorCallbackData* data = user_data;
if (offset == WASM_UNKNOWN_OFFSET) {
- print_error(data->ctx, CHECK_TYPE_FULL, data->loc,
+ print_error(data->ctx, CHECK_STYLE_FULL, data->loc,
"error in binary module: %s", error);
} else {
- print_error(data->ctx, CHECK_TYPE_FULL, data->loc,
+ print_error(data->ctx, CHECK_STYLE_FULL, data->loc,
"error in binary module: @0x%08x: %s", offset, error);
}
}
@@ -938,49 +1035,50 @@ static void check_raw_module(Context* ctx, WasmRawModule* raw) {
}
}
-static void check_invoke(Context* ctx,
- const WasmCommandInvoke* invoke,
- TypeSet return_type) {
+/* returns the result type of the invoked function, checked by the caller;
+ * returning WASM_CHECK_TYPE_ANY means that another error occured first, so the
+ * result type should be ignored. */
+static WasmCheckType check_invoke(Context* ctx,
+ const WasmCommandInvoke* invoke) {
const WasmModule* module = ctx->current_module;
if (!module) {
- print_error(ctx, CHECK_TYPE_FULL, &invoke->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &invoke->loc,
"invoke must occur after a module definition");
- return;
+ return WASM_CHECK_TYPE_ANY;
}
- WasmExport* export =
- wasm_get_export_by_name(module, &invoke->name);
+ WasmExport* export = wasm_get_export_by_name(module, &invoke->name);
if (!export) {
- print_error(ctx, CHECK_TYPE_NAME, &invoke->loc,
+ print_error(ctx, CHECK_STYLE_NAME, &invoke->loc,
"unknown function export \"" PRIstringslice "\"",
WASM_PRINTF_STRING_SLICE_ARG(invoke->name));
- return;
+ return WASM_CHECK_TYPE_ANY;
}
WasmFunc* func = wasm_get_func_by_var(module, &export->var);
if (!func) {
/* this error will have already been reported, just skip it */
- return;
+ return WASM_CHECK_TYPE_ANY;
}
size_t actual_args = invoke->args.size;
size_t expected_args = wasm_get_num_params(module, func);
if (expected_args != actual_args) {
- print_error(ctx, CHECK_TYPE_FULL, &invoke->loc,
+ print_error(ctx, CHECK_STYLE_FULL, &invoke->loc,
"too %s parameters to function. got %" PRIzd
", expected %" PRIzd,
actual_args > expected_args ? "many" : "few", actual_args,
expected_args);
- return;
+ return WASM_CHECK_TYPE_ANY;
}
- check_type_set(ctx, &invoke->loc, wasm_get_result_type(module, func),
- return_type, "");
size_t i;
for (i = 0; i < actual_args; ++i) {
WasmConst* const_ = &invoke->args.data[i];
- check_type_arg_exact(ctx, &const_->loc, const_->type,
- wasm_get_param_type(module, func, i), "invoke", i);
+ check_type_arg(ctx, &const_->loc, const_->type,
+ wasm_get_param_type(module, func, i), "invoke", i);
}
+
+ return wasm_get_result_type(module, func);
}
static void check_command(Context* ctx, const WasmCommand* command) {
@@ -990,25 +1088,36 @@ static void check_command(Context* ctx, const WasmCommand* command) {
break;
case WASM_COMMAND_TYPE_INVOKE:
- check_invoke(ctx, &command->invoke, WASM_TYPE_SET_VOID);
+ /* ignore result type */
+ check_invoke(ctx, &command->invoke);
break;
case WASM_COMMAND_TYPE_ASSERT_INVALID:
/* ignore */
break;
- case WASM_COMMAND_TYPE_ASSERT_RETURN:
- check_invoke(ctx, &command->assert_return.invoke,
- TYPE_TO_TYPE_SET(command->assert_return.expected.type));
+ case WASM_COMMAND_TYPE_ASSERT_RETURN: {
+ const WasmCommandInvoke* invoke = &command->assert_return.invoke;
+ WasmCheckType result_type = check_invoke(ctx, invoke);
+ if (result_type != WASM_CHECK_TYPE_ANY) {
+ check_type(ctx, &invoke->loc, result_type,
+ command->assert_return.expected.type, "invoke");
+ }
break;
+ }
- case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN:
- check_invoke(ctx, &command->assert_return_nan.invoke,
- WASM_TYPE_SET_F32 | WASM_TYPE_SET_F64);
+ case WASM_COMMAND_TYPE_ASSERT_RETURN_NAN: {
+ const WasmCommandInvoke* invoke = &command->assert_return_nan.invoke;
+ WasmCheckType result_type = check_invoke(ctx, invoke);
+ if (result_type != WASM_CHECK_TYPE_ANY) {
+ check_assert_return_nan_type(ctx, &invoke->loc, result_type, "invoke");
+ }
break;
+ }
case WASM_COMMAND_TYPE_ASSERT_TRAP:
- check_invoke(ctx, &command->assert_trap.invoke, WASM_TYPE_SET_VOID);
+ /* ignore result type */
+ check_invoke(ctx, &command->assert_trap.invoke);
break;
default:
@@ -1016,12 +1125,14 @@ static void check_command(Context* ctx, const WasmCommand* command) {
}
}
-WasmResult wasm_check_names(WasmAstLexer* lexer,
+WasmResult wasm_check_names(WasmAllocator* allocator,
+ WasmAstLexer* lexer,
const struct WasmScript* script,
WasmSourceErrorHandler* error_handler) {
Context ctx;
WASM_ZERO_MEMORY(ctx);
- ctx.check_type = CHECK_TYPE_NAME;
+ ctx.check_style = CHECK_STYLE_NAME;
+ ctx.allocator = allocator;
ctx.lexer = lexer;
ctx.error_handler = error_handler;
ctx.result = WASM_OK;
@@ -1031,12 +1142,14 @@ WasmResult wasm_check_names(WasmAstLexer* lexer,
return ctx.result;
}
-WasmResult wasm_check_ast(WasmAstLexer* lexer,
+WasmResult wasm_check_ast(WasmAllocator* allocator,
+ WasmAstLexer* lexer,
const struct WasmScript* script,
WasmSourceErrorHandler* error_handler) {
Context ctx;
WASM_ZERO_MEMORY(ctx);
- ctx.check_type = CHECK_TYPE_FULL;
+ ctx.check_style = CHECK_STYLE_FULL;
+ ctx.allocator = allocator;
ctx.lexer = lexer;
ctx.error_handler = error_handler;
ctx.result = WASM_OK;
@@ -1054,7 +1167,7 @@ WasmResult wasm_check_assert_invalid(
WasmSourceErrorHandler* error_handler) {
Context ctx;
WASM_ZERO_MEMORY(ctx);
- ctx.check_type = CHECK_TYPE_FULL;
+ ctx.check_style = CHECK_STYLE_FULL;
ctx.allocator = allocator;
ctx.lexer = lexer;
ctx.error_handler = error_handler;
@@ -1068,7 +1181,7 @@ WasmResult wasm_check_assert_invalid(
Context ai_ctx;
WASM_ZERO_MEMORY(ai_ctx);
- ai_ctx.check_type = CHECK_TYPE_FULL;
+ ai_ctx.check_style = CHECK_STYLE_FULL;
ai_ctx.allocator = allocator;
ai_ctx.lexer = lexer;
ai_ctx.error_handler = assert_invalid_error_handler;
@@ -1076,7 +1189,7 @@ WasmResult wasm_check_assert_invalid(
check_raw_module(&ai_ctx, &command->assert_invalid.module);
if (WASM_SUCCEEDED(ai_ctx.result)) {
- print_error(&ctx, CHECK_TYPE_FULL, &command->assert_invalid.module.loc,
+ print_error(&ctx, CHECK_STYLE_FULL, &command->assert_invalid.module.loc,
"expected module to be invalid");
}
}