commit 6c11668244aa2a3ce4288c24c626ca2225df0156
parent d5330de0042e9ef162947f4f3594b01cfdd035a2
Author: Sebastian <sebastian@sebsite.pw>
Date: Wed, 11 Jan 2023 18:25:50 -0500
check: make yield to outer scope a terminating expression
use os;
export fn main() void = {
:outer {
// should be int
const status = if (true) {
yield 0;
} else {
// should terminate
yield :outer;
};
os::exit(status);
};
};
Fixes: https://todo.sr.ht/~sircmpwn/hare/674
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -1674,7 +1674,17 @@ check_expr_compound(struct context *ctx,
}
}
- expr->terminates = lexpr->terminates && lexpr->type != EXPR_YIELD;
+ expr->terminates = false;
+ if (lexpr->terminates) {
+ expr->terminates = true;
+ if (lexpr->type == EXPR_YIELD) {
+ const char *llabel = lexpr->control.label;
+ if (!llabel || (scope->label
+ && strcmp(llabel, scope->label) == 0)) {
+ expr->terminates = false;
+ }
+ }
+ }
expr->result = type_store_reduce_result(ctx->store, aexpr->loc,
scope->results);
diff --git a/tests/12-loops.ha b/tests/12-loops.ha
@@ -96,6 +96,7 @@ fn label() void = {
assert(compile("fn test() void = { break :bar; };") as exited != EXIT_SUCCESS);
assert(compile("fn test() void = { :foo for (true) { :foo for (true) void; } ; };") as exited != EXIT_SUCCESS);
assert(compile("fn test() void = :foo { break :foo; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { for (true) { { break; }; void; }; };") as exited != EXIT_SUCCESS);
};
type abool = bool;
diff --git a/tests/33-yield.ha b/tests/33-yield.ha
@@ -1,3 +1,5 @@
+use rt::{compile, exited, EXIT_SUCCESS};
+
fn basics() void = {
let x = {
yield 10;
@@ -13,10 +15,16 @@ fn basics() void = {
};
fn termination() void = {
+ // XXX: reject tests have to go first because of
+ // https://todo.sr.ht/~sircmpwn/hare/660
+ assert(compile(
+ "fn test() void = { let x: int = if (true) { yield; } else 1; };"
+ ) as exited != EXIT_SUCCESS);
+
:outer {
- if (true) {
+ let x: int = if (true) {
yield :outer;
- } else void;
+ } else 1;
abort();
};
};