harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit ea1aedfc529e9f6a084f6ce2312c3fe7ba80318b
parent 6b47f370477d05dbd0fb7aa89052159367a4de2b
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Mon, 16 Aug 2021 21:39:22 +0000

check: refactor error list into context

And display the actual errors which happened rather than the awful old
"unresolvable identifier" message.

Signed-off-by: Eyal Sawady <ecs@d2evs.net>

Diffstat:
Minclude/check.h | 20++++++++++----------
Msrc/check.c | 872+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/type_store.c | 26++++++++++----------------
Mtests/30-reduction.c | 14++++++--------
4 files changed, 457 insertions(+), 475 deletions(-)

diff --git a/include/check.h b/include/check.h @@ -26,6 +26,12 @@ struct define { struct define *next; }; +struct errors { + struct location loc; + char *msg; + struct errors *next; +}; + struct context { struct modcache **modcache; struct define *defines; @@ -37,6 +43,8 @@ struct context { struct scope *scope; bool deferring; int id; + struct errors *errors; + struct errors **next; }; struct constant_decl { @@ -112,17 +120,9 @@ struct scope *check_internal(struct type_store *ts, struct unit *unit, bool scan_only); -struct errors { - struct location loc; - char *msg; - struct errors *next; - struct errors *prev; -}; - -struct errors *check_expression(struct context *ctx, +void check_expression(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors); + const struct type *hint); #endif diff --git a/src/check.c b/src/check.c @@ -42,9 +42,6 @@ static void handle_errors(struct errors *errors) { struct errors *error = errors; - while (error && error->prev) { - error = error->prev; - } while (error) { fprintf(stderr, "Error %s:%d:%d: %s\n", error->loc.path, error->loc.lineno, error->loc.colno, error->msg); @@ -57,13 +54,13 @@ handle_errors(struct errors *errors) } } -static struct errors * -error(const struct location loc, - struct expression *expr, - struct errors *errors, - char *fmt, ...) +static void +error(struct context *ctx, const struct location loc, struct expression *expr, + char *fmt, ...) { expr->type = EXPR_CONSTANT; + // TODO: We should have a separate type for errors, to avoid spurious + // errors expr->result = &builtin_type_void; expr->terminates = false; expr->loc = loc; @@ -77,15 +74,10 @@ error(const struct location loc, vsnprintf(msg, sz + 1, fmt, ap); va_end(ap); - - struct errors *next = xcalloc(1, sizeof(struct errors)); + struct errors *next = *ctx->next = xcalloc(1, sizeof(struct errors)); next->loc = loc; next->msg = msg; - next->prev = errors; - if (errors) { - errors->next = next; - } - return next; + ctx->next = &next->next; } static struct expression * @@ -112,12 +104,11 @@ lower_implicit_cast(const struct type *to, struct expression *expr) return cast; } -static struct errors * +static void check_expr_access(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_ACCESS; expr->access.type = aexpr->access.type; @@ -129,8 +120,9 @@ check_expr_access(struct context *ctx, char buf[1024]; identifier_unparse_static(&aexpr->access.ident, buf, sizeof(buf)); if (!obj) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Unknown object '%s'", buf); + return; } switch (obj->otype) { case O_CONST: @@ -144,9 +136,10 @@ check_expr_access(struct context *ctx, break; case O_TYPE: if (type_dealias(obj->type)->storage != STORAGE_VOID) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot use non-void type alias '%s' as constant", identifier_unparse(&obj->type->alias.ident)); + return; } expr->type = EXPR_CONSTANT; expr->result = obj->type; @@ -156,28 +149,29 @@ check_expr_access(struct context *ctx, case ACCESS_INDEX: expr->access.array = xcalloc(1, sizeof(struct expression)); expr->access.index = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->access.array, - expr->access.array, NULL, errors); - errors = check_expression(ctx, aexpr->access.index, - expr->access.index, &builtin_type_size, errors); + check_expression(ctx, aexpr->access.array, expr->access.array, NULL); + check_expression(ctx, aexpr->access.index, expr->access.index, &builtin_type_size); const struct type *atype = type_dereference(expr->access.array->result); if (!atype) { - return error(aexpr->access.array->loc, expr, errors, + error(ctx, aexpr->access.array->loc, expr, "Cannot dereference nullable pointer for indexing"); + return; } const struct type *itype = type_dealias(expr->access.index->result); if (atype->storage != STORAGE_ARRAY && atype->storage != STORAGE_SLICE) { - return error(aexpr->access.array->loc, expr, errors, + error(ctx, aexpr->access.array->loc, expr, "Cannot index non-array, non-slice %s object", type_storage_unparse(atype->storage)); + return; } if (!type_is_integer(itype)) { - return error(aexpr->access.index->loc, expr, errors, + error(ctx, aexpr->access.index->loc, expr, "Cannot use non-integer %s type as slice/array index", type_storage_unparse(itype->storage)); + return; } expr->access.index = lower_implicit_cast( &builtin_type_size, expr->access.index); @@ -186,71 +180,73 @@ check_expr_access(struct context *ctx, break; case ACCESS_FIELD: expr->access._struct = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->access._struct, - expr->access._struct, NULL, errors); + check_expression(ctx, aexpr->access._struct, expr->access._struct, NULL); const struct type *stype = type_dereference(expr->access._struct->result); if (!stype) { - return error(aexpr->access._struct->loc, expr, errors, + error(ctx, aexpr->access._struct->loc, expr, "Cannot dereference nullable pointer for field selection"); + return; } if (stype->storage != STORAGE_STRUCT && stype->storage != STORAGE_UNION) { - return error(aexpr->access._struct->loc, expr, errors, + error(ctx, aexpr->access._struct->loc, expr, "Cannot select field from non-struct, non-union object"); + return; } expr->access.field = type_get_field(stype, aexpr->access.field); if (!expr->access.field) { - return error(aexpr->access._struct->loc, expr, errors, + error(ctx, aexpr->access._struct->loc, expr, "No such struct field '%s'", aexpr->access.field); + return; } expr->result = expr->access.field->type; break; case ACCESS_TUPLE: expr->access.tuple = xcalloc(1, sizeof(struct expression)); struct expression *value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->access.tuple, - expr->access.tuple, NULL, errors); - errors = check_expression(ctx, aexpr->access.value, - value, NULL, errors); + check_expression(ctx, aexpr->access.tuple, expr->access.tuple, NULL); + check_expression(ctx, aexpr->access.value, value, NULL); assert(value->type == EXPR_CONSTANT); const struct type *ttype = type_dereference(expr->access.tuple->result); if (!ttype) { - return error(aexpr->access.tuple->loc, expr, errors, + error(ctx, aexpr->access.tuple->loc, expr, "Cannot dereference nullable pointer for value selection"); + return; } if (ttype->storage != STORAGE_TUPLE) { - return error(aexpr->access.tuple->loc, expr, errors, + error(ctx, aexpr->access.tuple->loc, expr, "Cannot select value from non-tuple object"); + return; } if (!type_is_integer(value->result)) { - return error(aexpr->access.tuple->loc, expr, errors, + error(ctx, aexpr->access.tuple->loc, expr, "Cannot use non-integer constant to select tuple value"); + return; } expr->access.tvalue = type_get_value(ttype, aexpr->access.value->constant.uval); if (!expr->access.tvalue) { - return error(aexpr->access.tuple->loc, expr, errors, + error(ctx, aexpr->access.tuple->loc, expr, "No such tuple value '%zu'", aexpr->access.value->constant.uval); + return; } expr->access.tindex = aexpr->access.value->constant.uval; expr->result = expr->access.tvalue->type; break; } - return errors; } -static struct errors * +static void check_expr_alloc(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { assert(aexpr->type == EXPR_ALLOC); expr->type = EXPR_ALLOC; @@ -261,8 +257,7 @@ check_expr_alloc(struct context *ctx, } else if (hint && type_dealias(hint)->storage == STORAGE_SLICE) { inittype = hint; } - errors = check_expression(ctx, aexpr->alloc.expr, expr->alloc.expr, - inittype, errors); + check_expression(ctx, aexpr->alloc.expr, expr->alloc.expr, inittype); inittype = expr->alloc.expr->result; int flags = 0; @@ -298,37 +293,37 @@ check_expr_alloc(struct context *ctx, switch (storage) { case STORAGE_POINTER: if (aexpr->alloc.cap != NULL) { - return error(aexpr->alloc.cap->loc, expr, errors, + error(ctx, aexpr->alloc.cap->loc, expr, "Allocation with capacity must be of slice type, not %s", type_storage_unparse(storage)); + return; } break; case STORAGE_SLICE: if (aexpr->alloc.cap != NULL) { expr->alloc.cap = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->alloc.cap, - expr->alloc.cap, &builtin_type_size, errors); + check_expression(ctx, aexpr->alloc.cap, expr->alloc.cap, &builtin_type_size); if (!type_is_assignable(&builtin_type_size, expr->alloc.cap->result)) { - return error(aexpr->alloc.cap->loc, expr, errors, + error(ctx, aexpr->alloc.cap->loc, expr, "Allocation capacity must be assignable to size"); + return; } } break; default: - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Allocation type must be pointer or slice, not %s", type_storage_unparse(storage)); + return; } - return errors; } -static struct errors * +static void check_expr_append(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { assert(aexpr->type == EXPR_APPEND); expr->type = EXPR_APPEND; @@ -336,26 +331,29 @@ check_expr_append(struct context *ctx, expr->append.is_static = aexpr->append.is_static; expr->insert.loc = aexpr->loc; expr->append.expr = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->append.expr, expr->append.expr, - NULL, errors); + check_expression(ctx, aexpr->append.expr, expr->append.expr, NULL); const struct type *stype = type_dereference(expr->append.expr->result); if (!stype) { - return error(aexpr->access.array->loc, expr, errors, + error(ctx, aexpr->access.array->loc, expr, "Cannot dereference nullable pointer for append"); + return; } if (stype->storage != STORAGE_SLICE) { - return error(aexpr->append.expr->loc, expr, errors, + error(ctx, aexpr->append.expr->loc, expr, "append must operate on a slice"); + return; } if (stype->flags & TYPE_CONST) { - return error(aexpr->append.expr->loc, expr, errors, + error(ctx, aexpr->append.expr->loc, expr, "append must operate on a mutable slice"); + return; } if (expr->append.expr->type != EXPR_ACCESS && (expr->append.expr->type != EXPR_UNARITHM || expr->append.expr->unarithm.op != UN_DEREF)) { - return error(aexpr->append.expr->loc, expr, errors, + error(ctx, aexpr->append.expr->loc, expr, "append must operate on a slice object"); + return; } const struct type *memb = stype->array.members; struct append_values **next = &expr->append.values; @@ -365,33 +363,31 @@ check_expr_append(struct context *ctx, xcalloc(sizeof(struct append_values), 1); value->expr = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, avalue->expr, value->expr, memb, - errors); + check_expression(ctx, avalue->expr, value->expr, memb); if (!type_is_assignable(memb, value->expr->result)) { - return error(avalue->expr->loc, expr, errors, + error(ctx, avalue->expr->loc, expr, "appended value must be assignable to member type"); + return; } value->expr = lower_implicit_cast(memb, value->expr); next = &value->next; } if (aexpr->append.variadic != NULL) { expr->append.variadic = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->append.variadic, - expr->append.variadic, stype, errors); + check_expression(ctx, aexpr->append.variadic, expr->append.variadic, stype); if (!type_is_assignable(stype, expr->append.variadic->result)) { - return error(aexpr->append.variadic->loc, expr, errors, + error(ctx, aexpr->append.variadic->loc, expr, "appended slice must be assignable to slice type"); + return; } } - return errors; } -static struct errors * +static void check_expr_assert(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_ASSERT; expr->result = &builtin_type_void; @@ -399,11 +395,11 @@ check_expr_assert(struct context *ctx, if (aexpr->assert.cond != NULL) { expr->assert.cond = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->assert.cond, - expr->assert.cond, &builtin_type_bool, errors); + check_expression(ctx, aexpr->assert.cond, expr->assert.cond, &builtin_type_bool); if (type_dealias(expr->assert.cond->result)->storage != STORAGE_BOOL) { - return error(aexpr->assert.cond->loc, expr, errors, + error(ctx, aexpr->assert.cond->loc, expr, "Assertion condition must be boolean"); + return; } } else { expr->terminates = true; @@ -411,11 +407,11 @@ check_expr_assert(struct context *ctx, expr->assert.message = xcalloc(1, sizeof(struct expression)); if (aexpr->assert.message != NULL) { - errors = check_expression(ctx, aexpr->assert.message, - expr->assert.message, &builtin_type_str, errors); + check_expression(ctx, aexpr->assert.message, expr->assert.message, &builtin_type_str); if (expr->assert.message->result->storage != STORAGE_STRING) { - return error(aexpr->assert.message->loc, expr, errors, + error(ctx, aexpr->assert.message->loc, expr, "Assertion message must be string"); + return; } assert(expr->assert.message->type == EXPR_CONSTANT); @@ -449,8 +445,9 @@ check_expr_assert(struct context *ctx, enum eval_result r = eval_expr(ctx, expr->assert.cond, &out); if (r != EVAL_OK) { - return error(aexpr->assert.cond->loc, expr, errors, + error(ctx, aexpr->assert.cond->loc, expr, "Unable to evaluate static assertion at compile time"); + return; } assert(out.result->storage == STORAGE_BOOL); cond = out.constant.bval; @@ -464,31 +461,29 @@ check_expr_assert(struct context *ctx, snprintf(format, 40, "Static assertion failed %%%lds", expr->assert.message->constant.string.len); if (aexpr->assert.cond == NULL) { - return error(aexpr->loc, - expr, - errors, format, + error(ctx, aexpr->loc, expr, format, expr->assert.message->constant.string.value); + return; } else { - return error(aexpr->assert.cond->loc, - expr, - errors, format, + error(ctx, aexpr->assert.cond->loc, + expr, format, expr->assert.message->constant.string.value); + return; }; } else { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Static assertion failed"); + return; } } } - return errors; } -static struct errors * +static void check_expr_assign(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_ASSIGN; expr->result = &builtin_type_void; @@ -496,55 +491,57 @@ check_expr_assign(struct context *ctx, struct expression *object = xcalloc(1, sizeof(struct expression)); struct expression *value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->assign.object, - object, NULL, errors); + check_expression(ctx, aexpr->assign.object, object, NULL); expr->assign.op = aexpr->assign.op; if (aexpr->assign.indirect) { const struct type *otype = type_dealias(object->result); if (otype->storage != STORAGE_POINTER) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot dereference non-pointer type for assignment"); + return; } if (otype->pointer.flags & PTR_NULLABLE) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot dereference nullable pointer type"); + return; } - errors = check_expression(ctx, aexpr->assign.value, value, - otype->pointer.referent, errors); + check_expression(ctx, aexpr->assign.value, value, otype->pointer.referent); if (!type_is_assignable(otype->pointer.referent, value->result)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Value type is not assignable to pointer type"); + return; } value = lower_implicit_cast(otype->pointer.referent, value); } else { - errors = check_expression(ctx, aexpr->assign.value, value, - object->result, errors); + check_expression(ctx, aexpr->assign.value, value, object->result); assert(object->type == EXPR_CONSTANT // If error || object->type == EXPR_ACCESS || object->type == EXPR_SLICE); // Invariant if (object->type == EXPR_SLICE) { if (expr->assign.op != BIN_LEQUAL) { - return error(aexpr->assign.object->loc, expr, errors, + error(ctx, aexpr->assign.object->loc, expr, "Slice assignments may not have a binop"); + return; } } if (object->result->flags & TYPE_CONST) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot assign to const object"); + return; } if (!type_is_assignable(object->result, value->result)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "rvalue type is not assignable to lvalue"); + return; } value = lower_implicit_cast(object->result, value); } expr->assign.object = object; expr->assign.value = value; - return errors; } static const struct type * @@ -672,12 +669,11 @@ aexpr_is_flexible(const struct ast_expression *expr) && storage_is_flexible(expr->constant.storage); } -static struct errors * +static void check_expr_binarithm(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_BINARITHM; expr->binarithm.op = aexpr->binarithm.op; @@ -718,10 +714,8 @@ check_expr_binarithm(struct context *ctx, *rvalue = xcalloc(1, sizeof(struct expression)); if (hint && lflex && rflex) { - errors = check_expression(ctx, aexpr->binarithm.lvalue, lvalue, - hint, errors); - errors = check_expression(ctx, aexpr->binarithm.rvalue, rvalue, - hint, errors); + check_expression(ctx, aexpr->binarithm.lvalue, lvalue, hint); + check_expression(ctx, aexpr->binarithm.rvalue, rvalue, hint); } else if (lflex && rflex) { intmax_t l = aexpr->binarithm.lvalue->constant.ival, r = aexpr->binarithm.rvalue->constant.ival, @@ -752,32 +746,25 @@ check_expr_binarithm(struct context *ctx, } } assert(storage != STORAGE_ICONST); - errors = check_expression(ctx, aexpr->binarithm.lvalue, lvalue, - builtin_type_for_storage(storage, false), errors); - errors = check_expression(ctx, aexpr->binarithm.rvalue, rvalue, - builtin_type_for_storage(storage, false), errors); + check_expression(ctx, aexpr->binarithm.lvalue, lvalue, builtin_type_for_storage(storage, false)); + check_expression(ctx, aexpr->binarithm.rvalue, rvalue, builtin_type_for_storage(storage, false)); } else if (!lflex && rflex) { - errors = check_expression(ctx, aexpr->binarithm.lvalue, lvalue, - hint, errors); - errors = check_expression(ctx, aexpr->binarithm.rvalue, rvalue, - lvalue->result, errors); + check_expression(ctx, aexpr->binarithm.lvalue, lvalue, hint); + check_expression(ctx, aexpr->binarithm.rvalue, rvalue, lvalue->result); } else if (lflex && !rflex) { - errors = check_expression(ctx, aexpr->binarithm.rvalue, rvalue, - hint, errors); - errors = check_expression(ctx, aexpr->binarithm.lvalue, lvalue, - rvalue->result, errors); + check_expression(ctx, aexpr->binarithm.rvalue, rvalue, hint); + check_expression(ctx, aexpr->binarithm.lvalue, lvalue, rvalue->result); } else { - errors = check_expression(ctx, aexpr->binarithm.lvalue, lvalue, - hint, errors); - errors = check_expression(ctx, aexpr->binarithm.rvalue, rvalue, - hint, errors); + check_expression(ctx, aexpr->binarithm.lvalue, lvalue, hint); + check_expression(ctx, aexpr->binarithm.rvalue, rvalue, hint); } const struct type *p = type_promote(ctx->store, lvalue->result, rvalue->result); if (p == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot promote lvalue and rvalue"); + return; } lvalue = lower_implicit_cast(p, lvalue); rvalue = lower_implicit_cast(p, rvalue); @@ -790,15 +777,13 @@ check_expr_binarithm(struct context *ctx, } else { expr->result = &builtin_type_bool; } - return errors; } -static struct errors * +static void check_expr_binding(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_BINDING; expr->result = &builtin_type_void; @@ -847,18 +832,19 @@ check_expr_binding(struct context *ctx, } } - errors = check_expression(ctx, abinding->initializer, - initializer, type, errors); + check_expression(ctx, abinding->initializer, initializer, type); if (context) { if (initializer->result->storage != STORAGE_ARRAY) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot infer array length from non-array type"); + return; } if (initializer->result->array.members != type->array.members) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Initializer is not assignable to binding type"); + return; } type = initializer->result; } @@ -879,12 +865,14 @@ check_expr_binding(struct context *ctx, } if (type->size == 0 || type->size == SIZE_UNDEFINED) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot create binding for type of zero or undefined size"); + return; } if (!type_is_assignable(type, initializer->result)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Initializer is not assignable to binding type"); + return; } binding->initializer = lower_implicit_cast(type, initializer); @@ -894,8 +882,9 @@ check_expr_binding(struct context *ctx, enum eval_result r = eval_expr( ctx, binding->initializer, value); if (r != EVAL_OK) { - return error(abinding->initializer->loc, expr, errors, + error(ctx, abinding->initializer->loc, expr, "Unable to evaluate static initializer at compile time"); + return; } // TODO: Free initializer binding->initializer = value; @@ -909,16 +898,14 @@ check_expr_binding(struct context *ctx, abinding = abinding->next; } - return errors; } // Lower Hare-style variadic arguments into an array literal -static struct errors * +static void lower_vaargs(struct context *ctx, const struct ast_call_argument *aarg, struct expression *vaargs, - const struct type *type, - struct errors *errors) + const struct type *type) { struct ast_expression val = { .type = EXPR_CONSTANT, @@ -942,11 +929,12 @@ lower_vaargs(struct context *ctx, // XXX: This error handling is minimum-effort and bad const struct type *hint = type_store_lookup_array( ctx->store, type, SIZE_UNDEFINED); - errors = check_expression(ctx, &val, vaargs, hint, errors); + check_expression(ctx, &val, vaargs, hint); if (vaargs->result->storage != STORAGE_ARRAY || vaargs->result->array.members != type) { - return error(val.loc, vaargs, errors, + error(ctx, val.loc, vaargs, "Argument is not assignable to variadic parameter type"); + return; } struct ast_array_constant *item = val.constant.array; @@ -955,31 +943,30 @@ lower_vaargs(struct context *ctx, free(item); item = next; } - return errors; } -static struct errors * +static void check_expr_call(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_CALL; struct expression *lvalue = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->call.lvalue, lvalue, NULL, - errors); + check_expression(ctx, aexpr->call.lvalue, lvalue, NULL); expr->call.lvalue = lvalue; const struct type *fntype = type_dereference(lvalue->result); if (!fntype) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot dereference nullable pointer type for function call"); + return; } if (fntype->storage != STORAGE_FUNCTION) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot call non-function type"); + return; } expr->result = fntype->func.result; if (fntype->func.flags & FN_NORETURN) { @@ -995,20 +982,20 @@ check_expr_call(struct context *ctx, if (!param->next && fntype->func.variadism == VARIADISM_HARE && !aarg->variadic) { - errors = lower_vaargs(ctx, aarg, arg->value, - param->type->array.members, errors); + lower_vaargs(ctx, aarg, arg->value, + param->type->array.members); arg->value = lower_implicit_cast(param->type, arg->value); param = NULL; aarg = NULL; break; } - errors = check_expression(ctx, aarg->value, arg->value, - param->type, errors); + check_expression(ctx, aarg->value, arg->value, param->type); if (!type_is_assignable(param->type, arg->value->result)) { - return error(aarg->value->loc, expr, errors, + error(ctx, aarg->value->loc, expr, "Argument is not assignable to parameter type"); + return; } arg->value = lower_implicit_cast(param->type, arg->value); @@ -1021,30 +1008,30 @@ check_expr_call(struct context *ctx, // No variadic arguments, lower to empty slice arg = *next = xcalloc(1, sizeof(struct call_argument)); arg->value = xcalloc(1, sizeof(struct expression)); - errors = lower_vaargs(ctx, NULL, arg->value, - param->type->array.members, errors); + lower_vaargs(ctx, NULL, arg->value, + param->type->array.members); arg->value = lower_implicit_cast(param->type, arg->value); param = param->next; } if (aarg) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Too many parameters for function call"); + return; } if (param) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Not enough parameters for function call"); + return; } - return errors; } -static struct errors * +static void check_expr_cast(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_CAST; expr->cast.kind = aexpr->cast.kind; @@ -1054,18 +1041,19 @@ check_expr_cast(struct context *ctx, type_store_lookup_atype(ctx->store, aexpr->cast.type); // TODO: Instead of allowing errors on casts to void, we should use a // different nonterminal - errors = check_expression(ctx, aexpr->cast.value, value, - secondary == &builtin_type_void ? NULL : secondary, errors); + check_expression(ctx, aexpr->cast.value, value, secondary == &builtin_type_void ? NULL : secondary); if (aexpr->cast.kind == C_ASSERTION || aexpr->cast.kind == C_TEST) { const struct type *primary = type_dealias(expr->cast.value->result); if (primary->storage != STORAGE_TAGGED) { - return error(aexpr->cast.value->loc, expr, errors, + error(ctx, aexpr->cast.value->loc, expr, "Expected a tagged union type"); + return; } if (!type_is_castable(value->result, secondary)) { - return error(aexpr->cast.type->loc, expr, errors, + error(ctx, aexpr->cast.type->loc, expr, "Invalid cast"); + return; } bool found = false; for (const struct type_tagged_union *t = &primary->tagged; @@ -1076,16 +1064,18 @@ check_expr_cast(struct context *ctx, } } if (!found) { - return error(aexpr->cast.type->loc, expr, errors, + error(ctx, aexpr->cast.type->loc, expr, "Type is not a valid member of the tagged union type"); + return; } } switch (aexpr->cast.kind) { case C_CAST: if (!type_is_castable(secondary, value->result)) { - return error(aexpr->cast.type->loc, expr, errors, + error(ctx, aexpr->cast.type->loc, expr, "Invalid cast"); + return; } // Fallthrough case C_ASSERTION: @@ -1095,15 +1085,13 @@ check_expr_cast(struct context *ctx, expr->result = &builtin_type_bool; break; } - return errors; } -static struct errors * +static void check_expr_array(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { size_t len = 0; bool expandable = false; @@ -1137,8 +1125,7 @@ check_expr_array(struct context *ctx, while (item) { struct expression *value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, item->value, value, type, - errors); + check_expression(ctx, item->value, value, type); cur = *next = xcalloc(1, sizeof(struct array_constant)); cur->value = value; @@ -1146,8 +1133,9 @@ check_expr_array(struct context *ctx, type = value->result; } else { if (!type_is_assignable(type, value->result)) { - return error(item->value->loc, expr, errors, + error(ctx, item->value->loc, expr, "Array members must be of a uniform type"); + return; } cur->value = lower_implicit_cast(type, cur->value); } @@ -1165,25 +1153,27 @@ check_expr_array(struct context *ctx, if (expandable) { if (hint == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot expand array for inferred type"); + return; } if (hint->storage != STORAGE_ARRAY || hint->array.length == SIZE_UNDEFINED || hint->array.length < len) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot expand array into destination type"); + return; } expr->result = type_store_lookup_array(ctx->store, type, hint->array.length); } else { if (type == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot infer array type from context, try casting it to the desired type"); + return; } expr->result = type_store_lookup_array(ctx->store, type, len); } - return errors; } static const struct type * @@ -1271,12 +1261,11 @@ lower_constant(const struct type *type, struct expression *expr) return NULL; } -static struct errors * +static void check_expr_constant(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_CONSTANT; expr->result = builtin_type_for_storage(aexpr->constant.storage, false); @@ -1289,8 +1278,9 @@ check_expr_constant(struct context *ctx, const struct type *type = lower_constant(hint, expr); if (!type) { // TODO: This error message is awful - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Integer constant out of range"); + return; } expr->result = type; } @@ -1303,8 +1293,9 @@ check_expr_constant(struct context *ctx, const struct type *type = lower_constant(hint, expr); if (!type) { // TODO: This error message is awful - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Floating constant out of range"); + return; } expr->result = type; } @@ -1317,8 +1308,9 @@ check_expr_constant(struct context *ctx, const struct type *type = lower_constant(hint, expr); if (!type) { // TODO: This error message is awful - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Rune constant out of range"); + return; } expr->result = type; } @@ -1351,7 +1343,7 @@ check_expr_constant(struct context *ctx, // No storage break; case STORAGE_ARRAY: - errors = check_expr_array(ctx, aexpr, expr, hint, errors); + check_expr_array(ctx, aexpr, expr, hint); break; case STORAGE_STRING: expr->constant.string.len = aexpr->constant.string.len; @@ -1377,44 +1369,39 @@ check_expr_constant(struct context *ctx, case STORAGE_UNION: assert(0); // Invariant } - return errors; } -static struct errors * +static void check_expr_defer(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { if (ctx->deferring) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot defer within another defer expression."); + return; } expr->type = EXPR_DEFER; expr->result = &builtin_type_void; expr->defer.deferred = xcalloc(1, sizeof(struct expression)); ctx->deferring = true; - errors = check_expression(ctx, aexpr->defer.deferred, - expr->defer.deferred, &builtin_type_void, errors); + check_expression(ctx, aexpr->defer.deferred, expr->defer.deferred, &builtin_type_void); ctx->deferring = false; - return errors; } -static struct errors * +static void check_expr_delete(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_DELETE; expr->delete.is_static = aexpr->delete.is_static; expr->result = &builtin_type_void; struct expression *dexpr = expr->delete.expr = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->delete.expr, expr->delete.expr, - NULL, errors); + check_expression(ctx, aexpr->delete.expr, expr->delete.expr, NULL); const struct type *otype = NULL; switch (dexpr->type) { case EXPR_SLICE: @@ -1422,36 +1409,38 @@ check_expr_delete(struct context *ctx, break; case EXPR_ACCESS: if (dexpr->access.type != ACCESS_INDEX) { - return error(aexpr->delete.expr->loc, expr, errors, + error(ctx, aexpr->delete.expr->loc, expr, "Deleted expression must be slicing or indexing expression"); + return; } otype = dexpr->access.array->result; break; default: - return error(aexpr->delete.expr->loc, expr, errors, + error(ctx, aexpr->delete.expr->loc, expr, "Deleted expression must be slicing or indexing expression"); + return; } otype = type_dealias(otype); while (otype->storage == STORAGE_POINTER) { otype = type_dealias(otype->pointer.referent); } if (otype->storage != STORAGE_SLICE) { - return error(aexpr->delete.expr->loc, expr, errors, + error(ctx, aexpr->delete.expr->loc, expr, "delete must operate on a slice"); + return; } if (otype->flags & TYPE_CONST) { - return error(aexpr->delete.expr->loc, expr, errors, + error(ctx, aexpr->delete.expr->loc, expr, "delete must operate on a mutable slice"); + return; } - return errors; } -static struct errors * +static void check_expr_control(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = aexpr->type; expr->result = &builtin_type_void; @@ -1471,18 +1460,17 @@ check_expr_control(struct context *ctx, } } if (scope == NULL) { - return error(aexpr->loc, expr, errors, "Unknown label %s", + error(ctx, aexpr->loc, expr, "Unknown label %s", expr->control.label); + return; } - return errors; } -static struct errors * +static void check_expr_for(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_FOR; expr->result = &builtin_type_void; @@ -1501,8 +1489,9 @@ check_expr_for(struct context *ctx, continue; } if (strcmp(scope->label, expr->_for.label) == 0){ - return error(aexpr->_for.label_loc, expr, errors, + error(ctx, aexpr->_for.label_loc, expr, "for loop label must be unique among its ancestors"); + return; } } } @@ -1512,81 +1501,71 @@ check_expr_for(struct context *ctx, if (aexpr->_for.bindings) { bindings = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_for.bindings, bindings, - NULL, errors); + check_expression(ctx, aexpr->_for.bindings, bindings, NULL); expr->_for.bindings = bindings; } cond = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_for.cond, cond, - &builtin_type_bool, errors); + check_expression(ctx, aexpr->_for.cond, cond, &builtin_type_bool); expr->_for.cond = cond; if (type_dealias(cond->result)->storage != STORAGE_BOOL) { - return error(aexpr->_for.cond->loc, expr, errors, + error(ctx, aexpr->_for.cond->loc, expr, "Expected for condition to be boolean"); + return; } if (aexpr->_for.afterthought) { afterthought = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_for.afterthought, - afterthought, &builtin_type_void, errors); + check_expression(ctx, aexpr->_for.afterthought, afterthought, &builtin_type_void); expr->_for.afterthought = afterthought; } body = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_for.body, body, - &builtin_type_void, errors); + check_expression(ctx, aexpr->_for.body, body, &builtin_type_void); expr->_for.body = body; scope_pop(&ctx->scope); - return errors; } -static struct errors * +static void check_expr_free(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { assert(aexpr->type == EXPR_FREE); expr->type = EXPR_FREE; expr->free.expr = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->free.expr, expr->free.expr, NULL, - errors); + check_expression(ctx, aexpr->free.expr, expr->free.expr, NULL); enum type_storage storage = type_dealias(expr->free.expr->result)->storage; if (storage != STORAGE_SLICE && storage != STORAGE_STRING && storage != STORAGE_POINTER) { - return error(aexpr->free.expr->loc, expr, errors, + error(ctx, aexpr->free.expr->loc, expr, "free must operate on slice, string, or pointer"); + return; } expr->result = &builtin_type_void; - return errors; } -static struct errors * +static void check_expr_if(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_IF; struct expression *cond, *true_branch, *false_branch = NULL; cond = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_if.cond, cond, - &builtin_type_bool, errors); + check_expression(ctx, aexpr->_if.cond, cond, &builtin_type_bool); true_branch = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_if.true_branch, true_branch, - hint, errors); + check_expression(ctx, aexpr->_if.true_branch, true_branch, hint); if (aexpr->_if.false_branch) { false_branch = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_if.false_branch, - false_branch, hint, errors); + check_expression(ctx, aexpr->_if.false_branch, false_branch, hint); bool tt = true_branch->terminates, ft = false_branch->terminates; if (tt && ft) { @@ -1610,8 +1589,9 @@ check_expr_if(struct context *ctx, expr->result = type_store_reduce_result(ctx->store, &tags); if (expr->result == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Invalid result type (dangling or ambiguous null)"); + return; } } true_branch = lower_implicit_cast(expr->result, true_branch); @@ -1622,22 +1602,21 @@ check_expr_if(struct context *ctx, } if (type_dealias(cond->result)->storage != STORAGE_BOOL) { - return error(aexpr->_if.cond->loc, expr, errors, + error(ctx, aexpr->_if.cond->loc, expr, "Expected if condition to be boolean"); + return; } expr->_if.cond = cond; expr->_if.true_branch = true_branch; expr->_if.false_branch = false_branch; - return errors; } -static struct errors * +static void check_expr_insert(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { assert(aexpr->type == EXPR_INSERT); expr->type = EXPR_INSERT; @@ -1645,25 +1624,27 @@ check_expr_insert(struct context *ctx, expr->insert.is_static = aexpr->insert.is_static; expr->insert.loc = aexpr->loc; expr->insert.expr = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->insert.expr, - expr->insert.expr, NULL, errors); + check_expression(ctx, aexpr->insert.expr, expr->insert.expr, NULL); // TODO: Handle dereferences assert(expr->insert.expr->type == EXPR_ACCESS && expr->insert.expr->access.type == ACCESS_INDEX); const struct type *sltype = expr->insert.expr->access.array->result; sltype = type_dereference(sltype); if (!sltype) { - return error(aexpr->access.array->loc, expr, errors, + error(ctx, aexpr->access.array->loc, expr, "Cannot dereference nullable pointer for insert"); + return; } if (sltype->storage != STORAGE_SLICE) { - return error(aexpr->insert.expr->loc, expr, errors, + error(ctx, aexpr->insert.expr->loc, expr, "cannot insert into non-slice type %s", type_storage_unparse(type_dealias(sltype)->storage)); + return; } if (sltype->flags & TYPE_CONST) { - return error(aexpr->insert.expr->loc, expr, errors, + error(ctx, aexpr->insert.expr->loc, expr, "insert must operate on a mutable slice"); + return; } const struct type *memb = type_dealias(sltype)->array.members; struct append_values **next = &expr->insert.values; @@ -1673,36 +1654,34 @@ check_expr_insert(struct context *ctx, xcalloc(sizeof(struct append_values), 1); value->expr = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, avalue->expr, - value->expr, memb, errors); + check_expression(ctx, avalue->expr, value->expr, memb); if (!type_is_assignable(memb, value->expr->result)) { - return error(avalue->expr->loc, expr, errors, + error(ctx, avalue->expr->loc, expr, "inserted value must be assignable to member type"); + return; } value->expr = lower_implicit_cast(memb, value->expr); next = &value->next; } if (aexpr->insert.variadic != NULL) { expr->insert.variadic = xcalloc(sizeof(struct expression), 1); - errors = check_expression(ctx, aexpr->insert.variadic, - expr->insert.variadic, sltype, errors); + check_expression(ctx, aexpr->insert.variadic, expr->insert.variadic, sltype); if (!type_is_assignable(sltype, expr->insert.variadic->result)) { - return error(aexpr->insert.variadic->loc, expr, errors, + error(ctx, aexpr->insert.variadic->loc, expr, "inserted slice type %s must be assignable to slice type", type_storage_unparse(expr->insert.variadic->result->storage)); + return; } expr->insert.variadic = lower_implicit_cast( sltype, expr->insert.variadic); } - return errors; } -static struct errors * +static void check_expr_list(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_LIST; @@ -1716,8 +1695,7 @@ check_expr_list(struct context *ctx, const struct ast_expression_list *alist = &aexpr->list; while (alist) { struct expression *lexpr = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, alist->expr, lexpr, - alist->next ? &builtin_type_void : hint, errors); + check_expression(ctx, alist->expr, lexpr, alist->next ? &builtin_type_void : hint); list->expr = lexpr; alist = alist->next; @@ -1732,28 +1710,26 @@ check_expr_list(struct context *ctx, } scope_pop(&ctx->scope); - return errors; } -static struct errors * +static void check_expr_match(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_MATCH; struct expression *value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->match.value, value, NULL, errors); - expr->match.value = value; + check_expression(ctx, aexpr->match.value, value, NULL); expr->match.value = value; const struct type *type = type_dealias(value->result); bool is_ptr = type->storage == STORAGE_POINTER && type->pointer.flags & PTR_NULLABLE; if (type->storage != STORAGE_TAGGED && !is_ptr) { - return error(aexpr->match.value->loc, expr, errors, + error(ctx, aexpr->match.value->loc, expr, "match value must be tagged union or nullable pointer type"); + return; } struct type_tagged_union result_type = {0}; @@ -1775,20 +1751,23 @@ check_expr_match(struct context *ctx, break; case STORAGE_POINTER: if (type->pointer.referent != ctype->pointer.referent) { - return error(acase->type->loc, expr, errors, + error(ctx, acase->type->loc, expr, "Match case on incompatible pointer type"); + return; } break; default: - return error(acase->type->loc, expr, errors, + error(ctx, acase->type->loc, expr, "Invalid type for match case (expected null or pointer type)"); + return; } } else { // TODO: Assign a score to tagged compatibility // and choose the branch with the highest score. if (!type_is_assignable(type, ctype)) { - return error(acase->type->loc, expr, errors, + error(ctx, acase->type->loc, expr, "Invalid type for match case (match is not assignable to this type)"); + return; } } } @@ -1806,8 +1785,7 @@ check_expr_match(struct context *ctx, _case->value = xcalloc(1, sizeof(struct expression)); _case->type = ctype; - errors = check_expression(ctx, acase->value, _case->value, - hint, errors); + check_expression(ctx, acase->value, _case->value, hint); if (acase->name) { scope_pop(&ctx->scope); @@ -1840,8 +1818,9 @@ check_expr_match(struct context *ctx, expr->result = type_store_reduce_result( ctx->store, &result_type); if (expr->result == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Invalid result type (dangling or ambiguous null)"); + return; } } @@ -1850,8 +1829,9 @@ check_expr_match(struct context *ctx, while (_case) { if (!_case->value->terminates && !type_is_assignable( expr->result, _case->value->result)) { - return error(acase->value->loc, expr, errors, + error(ctx, acase->value->loc, expr, "Match case is not assignable to result type"); + return; } _case->value = lower_implicit_cast( expr->result, _case->value); @@ -1866,15 +1846,13 @@ check_expr_match(struct context *ctx, tu = next; } } - return errors; } -static struct errors * +static void check_expr_measure(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_MEASURE; expr->result = &builtin_type_size; @@ -1883,19 +1861,20 @@ check_expr_measure(struct context *ctx, switch (expr->measure.op) { case M_LEN: expr->measure.value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->measure.value, - expr->measure.value, NULL, errors); + check_expression(ctx, aexpr->measure.value, expr->measure.value, NULL); enum type_storage vstor = type_dereference(expr->measure.value->result)->storage; bool valid = vstor == STORAGE_ARRAY || vstor == STORAGE_SLICE || vstor == STORAGE_STRING; if (!valid) { - return error(aexpr->measure.value->loc, expr, errors, + error(ctx, aexpr->measure.value->loc, expr, "len argument must be of an array, slice, or str type"); + return; } if (expr->measure.value->result->size == SIZE_UNDEFINED) { - return error(aexpr->measure.value->loc, expr, errors, + error(ctx, aexpr->measure.value->loc, expr, "Cannot take length of array type with undefined length"); + return; } break; case M_SIZE: @@ -1905,33 +1884,33 @@ check_expr_measure(struct context *ctx, case M_OFFSET: assert(0); // TODO } - return errors; } -static struct errors * +static void check_expr_propagate(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { struct expression *lvalue = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->propagate.value, lvalue, - hint == &builtin_type_void ? NULL : hint, errors); + check_expression(ctx, aexpr->propagate.value, lvalue, hint == &builtin_type_void ? NULL : hint); const struct type *intype = lvalue->result; if (type_dealias(intype)->storage != STORAGE_TAGGED) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot use error propagation with non-tagged type"); + return; } if (!aexpr->propagate.abort) { if (ctx->deferring) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot use error propagation in a defer expression"); + return; } if (ctx->fntype->func.flags & FN_NORETURN) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot use error propagation inside @noreturn function"); + return; } } @@ -1967,8 +1946,9 @@ check_expr_propagate(struct context *ctx, } if (!return_tagged.type) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "No error can occur here, cannot propagate"); + return; } const struct type *return_type; @@ -2053,8 +2033,9 @@ check_expr_propagate(struct context *ctx, case_err->value->assert.message->constant.string.len = n - 1; } else { if (!type_is_assignable(ctx->fntype->func.result, return_type)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Error type is not assignable to function result type"); + return; } case_err->value->type = EXPR_RETURN; @@ -2080,23 +2061,23 @@ check_expr_propagate(struct context *ctx, scope_pop(&ctx->scope); expr->result = result_type; - return errors; } -static struct errors * +static void check_expr_return(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { if (ctx->deferring) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot return inside a defer expression"); + return; } if (ctx->fntype->func.flags & FN_NORETURN) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot return inside @noreturn function"); + return; } expr->type = EXPR_RETURN; @@ -2105,59 +2086,58 @@ check_expr_return(struct context *ctx, struct expression *rval = xcalloc(1, sizeof(struct expression)); if (aexpr->_return.value) { - errors = check_expression(ctx, aexpr->_return.value, - rval, ctx->fntype->func.result, errors); + check_expression(ctx, aexpr->_return.value, rval, ctx->fntype->func.result); } else { rval->type = EXPR_CONSTANT; rval->result = &builtin_type_void; } if (!type_is_assignable(ctx->fntype->func.result, rval->result)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Return value is not assignable to function result type"); + return; } if (ctx->fntype->func.result != rval->result) { rval = lower_implicit_cast( ctx->fntype->func.result, rval); } expr->_return.value = rval; - return errors; } -static struct errors * +static void check_expr_slice(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_SLICE; expr->slice.object = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->slice.object, expr->slice.object, - NULL, errors); + check_expression(ctx, aexpr->slice.object, expr->slice.object, NULL); const struct type *atype = type_dereference(expr->slice.object->result); if (!atype) { - return error(aexpr->slice.object->loc, expr, errors, + error(ctx, aexpr->slice.object->loc, expr, "Cannot dereference nullable pointer for slicing"); + return; } if (atype->storage != STORAGE_SLICE && atype->storage != STORAGE_ARRAY) { - return error(aexpr->slice.object->loc, expr, errors, + error(ctx, aexpr->slice.object->loc, expr, "Cannot slice non-array, non-slice object"); + return; } const struct type *itype; if (aexpr->slice.start) { expr->slice.start = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->slice.start, - expr->slice.start, &builtin_type_size, errors); + check_expression(ctx, aexpr->slice.start, expr->slice.start, &builtin_type_size); itype = type_dealias(expr->slice.start->result); if (!type_is_integer(itype)) { - return error(aexpr->slice.start->loc, expr, errors, + error(ctx, aexpr->slice.start->loc, expr, "Cannot use non-integer %s type as slicing operand", type_storage_unparse(itype->storage)); + return; } expr->slice.start = lower_implicit_cast( &builtin_type_size, expr->slice.start); @@ -2165,32 +2145,31 @@ check_expr_slice(struct context *ctx, if (aexpr->slice.end) { expr->slice.end = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->slice.end, - expr->slice.end, &builtin_type_size, errors); + check_expression(ctx, aexpr->slice.end, expr->slice.end, &builtin_type_size); itype = type_dealias(expr->slice.end->result); if (!type_is_integer(itype)) { - return error(aexpr->slice.end->loc, expr, errors, + error(ctx, aexpr->slice.end->loc, expr, "Cannot use non-integer %s type as slicing operand", type_storage_unparse(itype->storage)); + return; } expr->slice.end = lower_implicit_cast( &builtin_type_size, expr->slice.end); } else if (atype->storage == STORAGE_ARRAY && atype->array.length == SIZE_UNDEFINED) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Must have end index on array of undefined length"); + return; } expr->result = type_store_lookup_slice(ctx->store, atype->array.members); - return errors; } -static struct errors * +static void check_expr_struct(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_STRUCT; @@ -2199,17 +2178,20 @@ check_expr_struct(struct context *ctx, const struct scope_object *obj = scope_lookup(ctx->scope, &aexpr->_struct.type); if (!obj) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Unknown type alias"); + return; } if (obj->otype != O_TYPE) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Name does not refer to a type"); + return; } stype = obj->type; if (type_dealias(stype)->storage != STORAGE_STRUCT) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Object named is not a struct type"); + return; } } @@ -2223,8 +2205,9 @@ check_expr_struct(struct context *ctx, struct expr_struct_field **snext = &sexpr->next; expr->_struct.autofill = aexpr->_struct.autofill; if (stype == NULL && expr->_struct.autofill) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Autofill is only permitted for named struct initializers"); + return; } struct ast_field_value *afield = aexpr->_struct.fields; @@ -2240,30 +2223,32 @@ check_expr_struct(struct context *ctx, ctx->store, tfield->field.type); } else { if (!afield->field.name) { - return error(afield->field.initializer->loc, - expr, errors, + error(ctx, afield->field.initializer->loc, + expr, "Anonymous fields are not permitted for named struct type"); + return; // XXX: ^ Is that correct? } sexpr->field = type_get_field(type_dealias(stype), afield->field.name); if (!sexpr->field) { - return error(afield->field.initializer->loc, - expr, errors, + error(ctx, afield->field.initializer->loc, + expr, "No field by this name exists for this type"); + return; } ftype = sexpr->field->type; } sexpr->value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, afield->field.initializer, - sexpr->value, ftype, errors); + check_expression(ctx, afield->field.initializer, sexpr->value, ftype); if (stype) { if (!type_is_assignable(sexpr->field->type, sexpr->value->result)) { - return error(afield->field.initializer->loc, - expr, errors, + error(ctx, afield->field.initializer->loc, + expr, "Initializer is not assignable to struct field"); + return; } sexpr->value = lower_implicit_cast( sexpr->field->type, sexpr->value); @@ -2295,13 +2280,15 @@ check_expr_struct(struct context *ctx, expr->result, tfield->field.name); if (!field) { // TODO: Use more specific error location - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "No field by this name exists for this type"); + return; } if (!type_is_assignable(field->type, sexpr->value->result)) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot initialize struct field '%s' from value of this type", field->name); + return; } sexpr->field = field; sexpr->value = lower_implicit_cast(field->type, sexpr->value); @@ -2314,21 +2301,18 @@ check_expr_struct(struct context *ctx, sexpr = sexpr->next; } } - return errors; } -static struct errors * +static void check_expr_switch(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_SWITCH; struct expression *value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->_switch.value, value, NULL, - errors); + check_expression(ctx, aexpr->_switch.value, value, NULL); const struct type *type = type_dealias(value->result); expr->_switch.value = value; @@ -2352,18 +2336,19 @@ check_expr_switch(struct context *ctx, struct expression *evaled = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aopt->value, value, type, - errors); + check_expression(ctx, aopt->value, value, type); if (!type_is_assignable(type_dealias(type), type_dealias(value->result))) { - return error(aopt->value->loc, expr, errors, + error(ctx, aopt->value->loc, expr, "Invalid type for switch case"); + return; } enum eval_result r = eval_expr(ctx, value, evaled); if (r != EVAL_OK) { - return error(aopt->value->loc, expr, errors, + error(ctx, aopt->value->loc, expr, "Unable to evaluate case at compile time"); + return; } opt->value = evaled; @@ -2371,8 +2356,7 @@ check_expr_switch(struct context *ctx, } _case->value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, acase->value, _case->value, hint, - errors); + check_expression(ctx, acase->value, _case->value, hint); if (_case->value->terminates) { continue; } @@ -2400,8 +2384,9 @@ check_expr_switch(struct context *ctx, expr->result = type_store_reduce_result( ctx->store, &result_type); if (expr->result == NULL) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Invalid result type (dangling or ambiguous null)"); + return; } } @@ -2410,8 +2395,9 @@ check_expr_switch(struct context *ctx, while (_case) { if (!_case->value->terminates && !type_is_assignable( expr->result, _case->value->result)) { - return error(acase->value->loc, expr, errors, + error(ctx, acase->value->loc, expr, "Switch case is not assignable to result type"); + return; } _case->value = lower_implicit_cast( expr->result, _case->value); @@ -2426,15 +2412,13 @@ check_expr_switch(struct context *ctx, tu = next; } } - return errors; } -static struct errors * +static void check_expr_tuple(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_TUPLE; @@ -2450,8 +2434,7 @@ check_expr_tuple(struct context *ctx, for (const struct ast_expression_tuple *atuple = &aexpr->tuple; atuple; atuple = atuple->next) { tuple->value = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, atuple->expr, tuple->value, - ttuple ? ttuple->type : NULL, errors); + check_expression(ctx, atuple->expr, tuple->value, ttuple ? ttuple->type : NULL); rtype->type = tuple->value->result; if (atuple->next) { @@ -2494,8 +2477,9 @@ check_expr_tuple(struct context *ctx, } } if (!expr->result) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Tuple value is not assignable to tagged union hint"); + return; } } else { expr->result = type_store_lookup_tuple(ctx->store, &result); @@ -2506,12 +2490,14 @@ check_expr_tuple(struct context *ctx, const struct ast_expression_tuple *atuple = &aexpr->tuple; while (etuple) { if (!ttuple) { - return error(atuple->expr->loc, expr, errors, + error(ctx, atuple->expr->loc, expr, "Too many values for tuple type"); + return; } if (!type_is_assignable(ttuple->type, etuple->value->result)) { - return error(atuple->expr->loc, expr, errors, + error(ctx, atuple->expr->loc, expr, "Value is not assignable to tuple value type"); + return; } etuple->value = lower_implicit_cast(ttuple->type, etuple->value); etuple = etuple->next; @@ -2519,55 +2505,58 @@ check_expr_tuple(struct context *ctx, ttuple = ttuple->next; } if (ttuple) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Too few values for tuple type"); + return; } - return errors; } -static struct errors * +static void check_expr_unarithm(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->type = EXPR_UNARITHM; struct expression *operand = xcalloc(1, sizeof(struct expression)); - errors = check_expression(ctx, aexpr->unarithm.operand, operand, NULL, - errors); + check_expression(ctx, aexpr->unarithm.operand, operand, NULL); expr->unarithm.operand = operand; expr->unarithm.op = aexpr->unarithm.op; switch (expr->unarithm.op) { case UN_LNOT: if (type_dealias(operand->result)->storage != STORAGE_BOOL) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot perform logical NOT (!) on non-boolean type"); + return; } expr->result = &builtin_type_bool; break; case UN_BNOT: if (!type_is_integer(operand->result)) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot perform binary NOT (~) on non-integer type"); + return; } if (type_is_signed(operand->result)) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot perform binary NOT (~) on signed type"); + return; } expr->result = operand->result; break; case UN_MINUS: case UN_PLUS: if (!type_is_numeric(operand->result)) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot perform operation on non-numeric type"); + return; } if (!type_is_signed(operand->result)) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot perform operation on unsigned type"); + return; } expr->result = operand->result; break; @@ -2577,121 +2566,122 @@ check_expr_unarithm(struct context *ctx, break; case UN_DEREF: if (type_dealias(operand->result)->storage != STORAGE_POINTER) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot de-reference non-pointer type"); + return; } if (type_dealias(operand->result)->pointer.flags & PTR_NULLABLE) { - return error(aexpr->unarithm.operand->loc, expr, errors, + error(ctx, aexpr->unarithm.operand->loc, expr, "Cannot dereference nullable pointer type"); + return; } expr->result = type_dealias(operand->result)->pointer.referent; break; } - return errors; } -struct errors * +void check_expression(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, - const struct type *hint, - struct errors *errors) + const struct type *hint) { expr->loc = aexpr->loc; switch (aexpr->type) { case EXPR_ACCESS: - errors = check_expr_access(ctx, aexpr, expr, hint, errors); + check_expr_access(ctx, aexpr, expr, hint); break; case EXPR_ALLOC: - errors = check_expr_alloc(ctx, aexpr, expr, hint, errors); + check_expr_alloc(ctx, aexpr, expr, hint); break; case EXPR_APPEND: - errors = check_expr_append(ctx, aexpr, expr, hint, errors); + check_expr_append(ctx, aexpr, expr, hint); break; case EXPR_ASSERT: - errors = check_expr_assert(ctx, aexpr, expr, hint, errors); + check_expr_assert(ctx, aexpr, expr, hint); break; case EXPR_ASSIGN: - errors = check_expr_assign(ctx, aexpr, expr, hint, errors); + check_expr_assign(ctx, aexpr, expr, hint); break; case EXPR_BINARITHM: - errors = check_expr_binarithm(ctx, aexpr, expr, hint, errors); + check_expr_binarithm(ctx, aexpr, expr, hint); break; case EXPR_BINDING: - errors = check_expr_binding(ctx, aexpr, expr, hint, errors); + check_expr_binding(ctx, aexpr, expr, hint); break; case EXPR_BREAK: case EXPR_CONTINUE: - errors = check_expr_control(ctx, aexpr, expr, hint, errors); + check_expr_control(ctx, aexpr, expr, hint); break; case EXPR_CALL: - errors = check_expr_call(ctx, aexpr, expr, hint, errors); + check_expr_call(ctx, aexpr, expr, hint); break; case EXPR_CAST: - errors = check_expr_cast(ctx, aexpr, expr, hint, errors); + check_expr_cast(ctx, aexpr, expr, hint); break; case EXPR_CONSTANT: - errors = check_expr_constant(ctx, aexpr, expr, hint, errors); + check_expr_constant(ctx, aexpr, expr, hint); break; case EXPR_DEFER: - errors = check_expr_defer(ctx, aexpr, expr, hint, errors); + check_expr_defer(ctx, aexpr, expr, hint); break; case EXPR_DELETE: - errors = check_expr_delete(ctx, aexpr, expr, hint, errors); + check_expr_delete(ctx, aexpr, expr, hint); break; case EXPR_FOR: - errors = check_expr_for(ctx, aexpr, expr, hint, errors); + check_expr_for(ctx, aexpr, expr, hint); break; case EXPR_FREE: - errors = check_expr_free(ctx, aexpr, expr, hint, errors); + check_expr_free(ctx, aexpr, expr, hint); break; case EXPR_IF: - errors = check_expr_if(ctx, aexpr, expr, hint, errors); + check_expr_if(ctx, aexpr, expr, hint); break; case EXPR_INSERT: - errors = check_expr_insert(ctx, aexpr, expr, hint, errors); + check_expr_insert(ctx, aexpr, expr, hint); break; case EXPR_LIST: - errors = check_expr_list(ctx, aexpr, expr, hint, errors); + check_expr_list(ctx, aexpr, expr, hint); break; case EXPR_MATCH: - errors = check_expr_match(ctx, aexpr, expr, hint, errors); + check_expr_match(ctx, aexpr, expr, hint); break; case EXPR_MEASURE: - errors = check_expr_measure(ctx, aexpr, expr, hint, errors); + check_expr_measure(ctx, aexpr, expr, hint); break; case EXPR_PROPAGATE: - errors = check_expr_propagate(ctx, aexpr, expr, hint, errors); + check_expr_propagate(ctx, aexpr, expr, hint); break; case EXPR_RETURN: - errors = check_expr_return(ctx, aexpr, expr, hint, errors); + check_expr_return(ctx, aexpr, expr, hint); break; case EXPR_SLICE: - errors = check_expr_slice(ctx, aexpr, expr, hint, errors); + check_expr_slice(ctx, aexpr, expr, hint); break; case EXPR_STRUCT: - errors = check_expr_struct(ctx, aexpr, expr, hint, errors); + check_expr_struct(ctx, aexpr, expr, hint); break; case EXPR_SWITCH: - errors = check_expr_switch(ctx, aexpr, expr, hint, errors); + check_expr_switch(ctx, aexpr, expr, hint); break; case EXPR_TUPLE: - errors = check_expr_tuple(ctx, aexpr, expr, hint, errors); + check_expr_tuple(ctx, aexpr, expr, hint); break; case EXPR_UNARITHM: - errors = check_expr_unarithm(ctx, aexpr, expr, hint, errors); + check_expr_unarithm(ctx, aexpr, expr, hint); break; } assert(expr->result); if (hint && hint->storage == STORAGE_VOID) { if ((expr->result->flags & TYPE_ERROR) != 0) { - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot ignore error here"); + return; } if (type_dealias(expr->result)->storage != STORAGE_TAGGED) { - return errors; + return; } const struct type_tagged_union *tu = &type_dealias(expr->result)->tagged; @@ -2699,11 +2689,11 @@ check_expression(struct context *ctx, if ((tu->type->flags & TYPE_ERROR) == 0) { continue; } - return error(aexpr->loc, expr, errors, + error(ctx, aexpr->loc, expr, "Cannot ignore error here"); + return; } } - return errors; } static struct declaration * @@ -2780,10 +2770,9 @@ check_function(struct context *ctx, } struct expression *body = xcalloc(1, sizeof(struct expression)); - struct errors *errors = check_expression(ctx, afndecl->body, body, - fntype->func.result, NULL); + check_expression(ctx, afndecl->body, body, fntype->func.result); // TODO: Pass errors up and deal with them at the end of check - handle_errors(errors); + handle_errors(ctx->errors); expect(&afndecl->body->loc, body->terminates || type_is_assignable(fntype->func.result, body->result), @@ -2823,10 +2812,9 @@ check_global(struct context *ctx, // TODO: Free initialier struct expression *initializer = xcalloc(1, sizeof(struct expression)); - struct errors *errors = check_expression(ctx, adecl->init, initializer, - type, NULL); + check_expression(ctx, adecl->init, initializer, type); // TODO: Pass errors up and deal with them at the end of check - handle_errors(errors); + handle_errors(ctx->errors); expect(&adecl->init->loc, type_is_assignable(type, initializer->result), @@ -3237,15 +3225,8 @@ scan_const(struct context *ctx, const struct ast_global_decl *decl) // TODO: Free the initializer struct expression *initializer = xcalloc(1, sizeof(struct expression)); - struct errors *errors = check_expression(ctx, decl->init, initializer, - type, NULL); - if (errors != NULL) { - struct errors *next = errors; - while (next) { - struct errors *tmp = next->next; - free(next); - next = tmp; - } + check_expression(ctx, decl->init, initializer, type); + if (ctx->errors != NULL) { return false; } @@ -3320,9 +3301,8 @@ scan_global(struct context *ctx, const struct ast_global_decl *decl) // TODO: Free initialier struct expression *initializer = xcalloc(1, sizeof(struct expression)); - struct errors *errors = check_expression(ctx, decl->init, - initializer, type, NULL); - if (errors != NULL) { + check_expression(ctx, decl->init, initializer, type); + if (ctx->errors != NULL) { return false; } expect(&decl->init->loc, @@ -3568,6 +3548,7 @@ check_internal(struct type_store *ts, ctx.store->check_context = &ctx; ctx.modcache = cache; ctx.defines = defines; + ctx.next = &ctx.errors; // Top-level scope management involves: // @@ -3590,10 +3571,9 @@ check_internal(struct type_store *ts, expect(&loc, type != NULL, "Unable to resolve type"); struct expression *initializer = xcalloc(1, sizeof(struct expression)); - struct errors *errors = check_expression(&ctx, - def->initializer, initializer, type, NULL); + check_expression(&ctx, def->initializer, initializer, type); // TODO: This could be more detailed - expect(&loc, errors == NULL, "Invalid initializer"); + expect(&loc, ctx.errors == NULL, "Invalid initializer"); expect(&loc, type_is_assignable(type, initializer->result), "Constant type is not assignable from initializer type"); initializer = lower_implicit_cast(type, initializer); @@ -3651,8 +3631,6 @@ check_internal(struct type_store *ts, *next = xcalloc(1, sizeof(struct scopes)); new->scope = (*next)->scope = scope_pop(&ctx.scope); next = &(*next)->next; - - } // Second pass populates the type graph @@ -3660,18 +3638,20 @@ check_internal(struct type_store *ts, while (cur || unresolved) { if (!cur) { if (!found) { - const struct ast_decls *d = - unresolved->unresolved; - while (d->next) { - d = d->next; - } - expect(&d->decl.loc, false, - "Unresolvable identifier"); + handle_errors(ctx.errors); } cur = unresolved; unresolved = NULL; found = false; } + struct errors *error = ctx.errors; + while (error) { + struct errors *next = error->next; + free(error); + error = next; + } + ctx.errors = NULL; + ctx.next = &ctx.errors; ctx.scope = cur->scope; ctx.store->check_context = &ctx; struct ast_decls *left = @@ -3701,12 +3681,22 @@ check_internal(struct type_store *ts, struct unresolveds *tmp = cur; cur = tmp->next; free(tmp); + } if (scan_only) { return ctx.unit; } + struct errors *error = ctx.errors; + while (error) { + struct errors *next = error->next; + free(error); + error = next; + } + ctx.errors = NULL; + ctx.next = &ctx.errors; + // Third pass populates the expression graph struct scopes *scope = subunit_scopes; struct declarations **next_decl = &unit->declarations; diff --git a/src/type_store.c b/src/type_store.c @@ -29,9 +29,6 @@ static void handle_errors(struct errors *errors) { struct errors *error = errors; - while (error && error->prev) { - error = error->prev; - } while (error) { fprintf(stderr, "Error %s:%d:%d: %s\n", error->loc.path, error->loc.lineno, error->loc.colno, error->msg); @@ -63,11 +60,10 @@ ast_array_len(struct type_store *store, const struct ast_type *atype) if (atype->array.length == NULL) { return SIZE_UNDEFINED; } - struct errors *errors = check_expression(store->check_context, - atype->array.length, &in, NULL, NULL); - handle_errors(errors); - enum eval_result r = eval_expr(store->check_context, &in, &out); + check_expression(store->check_context, atype->array.length, &in, NULL); // TODO: Bubble up these errors: + handle_errors(store->check_context->errors); + enum eval_result r = eval_expr(store->check_context, &in, &out); assert(r == EVAL_OK); assert(type_is_integer(out.result)); if (type_is_signed(out.result)) { @@ -190,11 +186,10 @@ struct_insert_field(struct type_store *store, struct struct_field **fields, if (atype->offset) { *ccompat = false; struct expression in, out; - struct errors *errors = check_expression(store->check_context, - atype->offset, &in, NULL, NULL); - handle_errors(errors); - enum eval_result r = eval_expr(store->check_context, &in, &out); + check_expression(store->check_context, atype->offset, &in, NULL); // TODO: Bubble up + handle_errors(store->check_context->errors); + enum eval_result r = eval_expr(store->check_context, &in, &out); assert(r == EVAL_OK); assert(type_is_integer(out.result)); if (type_is_signed(out.result)) { @@ -567,13 +562,12 @@ type_init_from_atype(struct type_store *store, value->name = strdup(avalue->name); if (avalue->value != NULL) { struct expression in, out; - struct errors *errors = check_expression( - store->check_context, avalue->value, - &in, storage, NULL); - handle_errors(errors); + check_expression(store->check_context, + avalue->value, &in, storage); + // TODO: Bubble this up + handle_errors(store->check_context->errors); enum eval_result r = eval_expr(store->check_context, &in, &out); - // TODO: Bubble this up assert(r == EVAL_OK && type_is_assignable(storage, out.result)); if (type_is_signed(storage)) { iimplicit = out.constant.ival; diff --git a/tests/30-reduction.c b/tests/30-reduction.c @@ -14,6 +14,8 @@ void test(struct context *ctx, char *expected, char *input) { builtin_types_init(); + ctx->errors = NULL; + ctx->next = &ctx->errors; const struct type *etype = NULL; if (strlen(expected) != 0) { @@ -29,18 +31,14 @@ void test(struct context *ctx, char *expected, char *input) { lex_init(&ilex, ibuf, "<input>"); struct ast_expression *iaexpr = parse_expression(&ilex); struct expression iexpr = {0}; - struct errors *errors = check_expression(ctx, iaexpr, &iexpr, NULL, - NULL); + check_expression(ctx, iaexpr, &iexpr, NULL); if (etype == NULL) { - assert(errors != NULL); + assert(ctx->errors != NULL); return; } - struct errors *error = errors; - while (error && error->prev) { - error = error->prev; - } + struct errors *error = ctx->errors; while (error) { fprintf(stderr, "Error %s:%d:%d: %s\n", error->loc.path, error->loc.lineno, error->loc.colno, error->msg); @@ -48,7 +46,7 @@ void test(struct context *ctx, char *expected, char *input) { free(error); error = next; } - if (errors) { + if (ctx->errors) { exit(EXIT_FAILURE); }