harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

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:
Msrc/check.c | 12+++++++++++-
Mtests/12-loops.ha | 1+
Mtests/33-yield.ha | 12++++++++++--
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(); }; };