harec

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

commit b01a5c5ab3965879b62fe5bb64a0811e35d78d04
parent 28e7b7036bca738f771a8676b4dcf7f9bc5c63d0
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 23 Feb 2021 13:27:53 -0500

check: lower error propagation to match expression

Diffstat:
Msrc/check.c | 66+++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/gen.c | 2+-
2 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -1564,20 +1564,13 @@ check_expr_propagate(struct context *ctx, const struct type *hint) { trenter(TR_CHECK, "propagate"); - expr->type = EXPR_PROPAGATE; - struct expression *lvalue = xcalloc(1, sizeof(struct expression)); check_expression(ctx, aexpr->propagate.value, lvalue, hint); - expr->propagate.value = lvalue; const struct type *intype = lvalue->result; - if (type_dealias(intype)->storage != STORAGE_TAGGED) { - expect(&aexpr->loc, - intype->flags & TYPE_ERROR, - "No error can occur here, cannot propagate"); - expr->result = &builtin_type_void; - return; - } + expect(&aexpr->loc, + type_dealias(intype)->storage, + "Cannot use error propagation with non-tagged type"); struct type_tagged_union result_tagged = {0}; struct type_tagged_union *tagged = &result_tagged, @@ -1631,10 +1624,61 @@ check_expr_propagate(struct context *ctx, result_type = result_tagged.type; } - expr->result = result_type; expect(&aexpr->loc, type_is_assignable(ctx->fntype->func.result, return_type), "Error type is not assignable to function result type"); + + // Lower to a match expression + expr->type = EXPR_MATCH; + expr->match.value = lvalue; + + struct scope *scope = scope_push(&ctx->scope, TR_CHECK); + scope->type = EXPR_MATCH; + struct match_case *case_ok = xcalloc(1, sizeof(struct match_case)); + struct match_case *case_err = xcalloc(1, sizeof(struct match_case)); + struct identifier ok_name = {0}, err_name = {0}; + + int n = snprintf(NULL, 0, "ok.%d", ctx->id); + ok_name.name = xcalloc(n + 1, 1); + snprintf(ok_name.name, n + 1, "ok.%d", ctx->id); + ++ctx->id; + const struct scope_object *ok_obj = scope_insert(scope, O_BIND, + &ok_name, &ok_name, result_type, NULL); + + n = snprintf(NULL, 0, "err.%d", ctx->id); + err_name.name = xcalloc(n + 1, 1); + snprintf(err_name.name, n + 1, "err.%d", ctx->id); + ++ctx->id; + const struct scope_object *err_obj = scope_insert(scope, O_BIND, + &err_name, &err_name, return_type, NULL); + + case_ok->type = result_type; + case_ok->object = ok_obj; + case_ok->value = xcalloc(1, sizeof(struct expression)); + case_ok->value->type = EXPR_ACCESS; + case_ok->value->access.type = ACCESS_IDENTIFIER; + case_ok->value->access.object = ok_obj; + case_ok->value->result = result_type; + + case_err->type = return_type; + case_err->object = err_obj; + case_err->value = xcalloc(1, sizeof(struct expression)); + case_err->value->type = EXPR_RETURN; + case_err->value->terminates = true; + case_err->value->result = &builtin_type_void; + struct expression *rval = + xcalloc(1, sizeof(struct expression)); + rval->type = EXPR_ACCESS; + rval->access.type = ACCESS_IDENTIFIER; + rval->access.object = err_obj; + rval->result = return_type; + case_err->value->_return.value = lower_implicit_cast( + ctx->fntype->func.result, rval); + + expr->match.cases = case_ok; + case_ok->next = case_err; + + expr->result = result_type; } static void diff --git a/src/gen.c b/src/gen.c @@ -2571,7 +2571,7 @@ gen_expression(struct gen_context *ctx, gen_expr_measure(ctx, expr, out); break; case EXPR_PROPAGATE: - assert(0); // TODO + assert(0); // Lowered in check case EXPR_RETURN: gen_expr_return(ctx, expr, out); break;