aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-08-05 12:19:57 +0100
committergingerBill <bill@gingerbill.org>2022-08-05 12:19:57 +0100
commita58e4d035964275ade5e09fa6bcafb5d46cc46e2 (patch)
tree85c404591463f4a19d46af638939a92b22ac28db /src/check_expr.cpp
parent576914aee1565618d8448a2bbc3cbef0c4acc4d1 (diff)
Allow for `foo() or_else unreachable()` and other diverging procedures
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp26
1 files changed, 23 insertions, 3 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index cf9f2f751..96adde013 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -119,6 +119,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint);
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
+bool is_diverging_expr(Ast *expr);
void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
auto results = did_you_mean_results(d);
@@ -7399,8 +7400,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
return Expr_Expr;
}
- check_multi_expr_with_type_hint(c, &y, default_value, x.type);
- error_operand_no_value(&y);
+ bool y_is_diverging = false;
+ check_expr_base(c, &y, default_value, x.type);
+ switch (y.mode) {
+ case Addressing_NoValue:
+ if (is_diverging_expr(y.expr)) {
+ // Allow
+ y.mode = Addressing_Value;
+ y_is_diverging = true;
+ } else {
+ error_operand_no_value(&y);
+ y.mode = Addressing_Invalid;
+ }
+ break;
+ case Addressing_Type:
+ error_operand_not_expression(&y);
+ y.mode = Addressing_Invalid;
+ break;
+ }
+
if (y.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
@@ -7414,7 +7432,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
if (left_type != nullptr) {
- check_assignment(c, &y, left_type, name);
+ if (!y_is_diverging) {
+ check_assignment(c, &y, left_type, name);
+ }
} else {
check_or_else_expr_no_value_error(c, name, x, type_hint);
}