harec

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

commit 28e7b7036bca738f771a8676b4dcf7f9bc5c63d0
parent abd2a236e806b555c6207bb60adc83c1f618976c
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 23 Feb 2021 11:42:50 -0500

check: implement error propagation

Diffstat:
Minclude/expr.h | 5+++++
Msrc/check.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/include/expr.h b/include/expr.h @@ -242,6 +242,10 @@ struct expression_measure { }; }; +struct expression_propagate { + struct expression *value; +}; + struct expression_return { struct expression *value; }; @@ -321,6 +325,7 @@ struct expression { struct expression_list list; struct expression_match match; struct expression_measure measure; + struct expression_propagate propagate; struct expression_return _return; struct expression_switch _switch; struct expression_struct _struct; diff --git a/src/check.c b/src/check.c @@ -1558,6 +1558,86 @@ check_expr_measure(struct context *ctx, } static void +check_expr_propagate(struct context *ctx, + const struct ast_expression *aexpr, + struct expression *expr, + 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; + } + + struct type_tagged_union result_tagged = {0}; + struct type_tagged_union *tagged = &result_tagged, + **next_tag = &tagged->next; + + struct type_tagged_union return_tagged = {0}; + struct type_tagged_union *rtagged = &return_tagged, + **next_rtag = &tagged->next; + + const struct type_tagged_union *intu = &type_dealias(intype)->tagged; + for (; intu; intu = intu->next) { + if (intu->type->flags & TYPE_ERROR) { + if (rtagged->type) { + rtagged = *next_rtag = + xcalloc(1, sizeof(struct type_tagged_union)); + next_rtag = &tagged->next; + rtagged->type = intu->type; + } else { + rtagged->type = intu->type; + } + } else { + if (tagged->type) { + tagged = *next_tag = + xcalloc(1, sizeof(struct type_tagged_union)); + next_tag = &tagged->next; + tagged->type = intu->type; + } else { + tagged->type = intu->type; + } + } + } + + expect(&aexpr->loc, return_tagged.type, + "No error can occur here, cannot propagate"); + + const struct type *return_type; + if (return_tagged.next) { + return_type = type_store_lookup_tagged( + ctx->store, &return_tagged); + } else { + return_type = return_tagged.type; + } + + const struct type *result_type; + if (!result_tagged.type) { + result_type = &builtin_type_void; + } else if (result_tagged.next) { + result_type = type_store_lookup_tagged( + ctx->store, &result_tagged); + } else { + 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"); +} + +static void check_expr_return(struct context *ctx, const struct ast_expression *aexpr, struct expression *expr, @@ -2041,7 +2121,8 @@ check_expression(struct context *ctx, check_expr_measure(ctx, aexpr, expr, hint); break; case EXPR_PROPAGATE: - assert(0); // TODO + check_expr_propagate(ctx, aexpr, expr, hint); + break; case EXPR_RETURN: check_expr_return(ctx, aexpr, expr, hint); break;