harec

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

commit aec1d1840df604d3d3dd83ad4c8404a4c0097c5e
parent 7737b24cefefc24e262e386e821dbacdbb7daa2b
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 31 Aug 2021 14:41:53 +0200

Use yields to determine expression list result type

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/expr.h | 1+
Minclude/scope.h | 9+++++++++
Mrt/+linux/syscalls.ha | 2+-
Mrt/abort.ha | 3++-
Mrt/malloc.ha | 2+-
Msrc/check.c | 38+++++++++++++++++++++++++++-----------
Msrc/gen.c | 8++++++++
Mtests/10-binarithms.ha | 1-
Mtests/14-switch.ha | 12++++++------
Atests/33-yield.ha | 25+++++++++++++++++++++++++
Mtests/configure | 3++-
11 files changed, 82 insertions(+), 22 deletions(-)

diff --git a/include/expr.h b/include/expr.h @@ -140,6 +140,7 @@ struct expression_cast { enum cast_kind kind; const struct type *secondary; struct expression *value; + bool lowered; }; struct call_argument { diff --git a/include/scope.h b/include/scope.h @@ -35,12 +35,21 @@ enum scope_class { SCOPE_UNIT, }; +struct expression; + +struct yield { + struct expression **expression; + struct yield *next; +}; + struct scope { enum scope_class class; const char *label; struct scope *parent; + const struct type *hint; struct type_tagged_union *results; + struct yield *yields; // Linked list in insertion order // Used for function parameters, where order matters diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -96,7 +96,7 @@ export fn mmap( flags: u64, fd: u64, offs: u64): u64; return if (r: int == -EPERM && addr == null && flags & MAP_ANON > 0 && flags & MAP_FIXED == 0) { - -ENOMEM: uintptr: *void; // Fix up incorrect EPERM from kernel + yield -ENOMEM: uintptr: *void; // Fix up incorrect EPERM from kernel } else r: uintptr: *void; }; diff --git a/rt/abort.ha b/rt/abort.ha @@ -11,7 +11,8 @@ const reasons: [_]str = [ "slice or array access out of bounds", // 0 "type assertion failed", // 1 "out of memory", // 2 - "unreachable code", // 3 + "static append exceeds slice capacity", // 3 + "unreachable code", // 4 ]; export @noreturn fn abort_fixed(loc: str, i: int) void = { diff --git a/rt/malloc.ha b/rt/malloc.ha @@ -81,7 +81,7 @@ fn malloc_small(n: size) nullable *void = { return if (p != null) { let q = *(p: **void); bins[b] = q; - p; + yield p; } else null; }; diff --git a/src/check.c b/src/check.c @@ -101,6 +101,7 @@ lower_implicit_cast(const struct type *to, struct expression *expr) cast->terminates = false; cast->cast.kind = C_CAST; cast->cast.value = expr; + cast->cast.lowered = true; return cast; } @@ -1286,7 +1287,8 @@ check_expr_compound(struct context *ctx, struct expression *lexpr; while (alist) { lexpr = xcalloc(1, sizeof(struct expression)); - check_expression(ctx, alist->expr, lexpr, alist->next ? &builtin_type_void : hint); + check_expression(ctx, alist->expr, lexpr, + alist->next ? &builtin_type_void : hint); list->expr = lexpr; alist = alist->next; @@ -1295,19 +1297,27 @@ check_expr_compound(struct context *ctx, list = *next; next = &list->next; } + if (alist && lexpr->terminates) { + error(ctx, alist->expr->loc, expr, + "A terminating expression may not be followed by additional expressions"); + } } - if (!lexpr->terminates) { - struct type_tagged_union *result = - xcalloc(1, sizeof(struct type_tagged_union)); - result->type = lexpr->result; - result->next = scope->results; - scope->results = result; + expr->terminates = lexpr->terminates && lexpr->type != EXPR_YIELD; + expr->result = type_store_reduce_result(ctx->store, scope->results); + + for (struct yield *yield = scope->yields; yield;) { + struct expression *lowered = lower_implicit_cast( + expr->result, *yield->expression); + if (*yield->expression != lowered) { + *yield->expression = lowered; + } + + struct yield *next = yield->next; + free(yield); + yield = next; } - expr->terminates = lexpr->terminates; - expr->result = type_store_reduce_result(ctx->store, scope->results); - // TODO: Cast all yields to this type assert(expr->result); scope_pop(&ctx->scope); } @@ -1495,8 +1505,8 @@ check_expr_control(struct context *ctx, { expr->type = aexpr->type; expr->result = &builtin_type_void; - expr->terminates = true; expr->control.label = aexpr->control.label; + expr->terminates = true; enum scope_class want; switch (expr->type) { @@ -1524,11 +1534,17 @@ check_expr_control(struct context *ctx, expr->control.value = xcalloc(1, sizeof(struct expression)); check_expression(ctx, aexpr->control.value, expr->control.value, scope->hint); + struct type_tagged_union *result = xcalloc(1, sizeof(struct type_tagged_union)); result->type = expr->control.value->result; result->next = scope->results; scope->results = result; + + struct yield *yield = xcalloc(1, sizeof(struct yield)); + yield->expression = &expr->control.value; + yield->next = scope->yields; + scope->yields = yield; } } diff --git a/src/gen.c b/src/gen.c @@ -1155,6 +1155,10 @@ gen_expr_cast_at(struct gen_context *ctx, return; } + if (expr->cast.lowered) { + pushc(ctx->current, "gen lowered cast"); + } + const struct type *to = expr->result; switch (type_dealias(to)->storage) { case STORAGE_SLICE: @@ -1192,6 +1196,10 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr) return out; } + if (expr->cast.lowered) { + pushc(ctx->current, "gen lowered cast"); + } + // Special cases switch (type_dealias(to)->storage) { case STORAGE_POINTER: diff --git a/tests/10-binarithms.ha b/tests/10-binarithms.ha @@ -1,6 +1,5 @@ fn error() bool = { abort(); - return false; }; fn set(x: *int) bool = { diff --git a/tests/14-switch.ha b/tests/14-switch.ha @@ -3,11 +3,11 @@ fn basics() void = { for (let i = 0z; i < len(cases); i += 1) { let x = cases[i][0]; let y: int = switch (x) { - 0 => x + 1, - 1 => x + 2, + 0 => x + 1, + 1 => x + 2, 10, 11, 12 => x + 10, - * => { - x; + * => { + yield x; }, }; assert(y == cases[i][1]); @@ -28,14 +28,14 @@ fn tagged_result() void = { let x = 42; let y: (int | uint) = switch (x) { 42 => 1337i, - * => 1337u, + * => 1337u, }; assert(y is int); x = 24; y = switch (x) { 42 => 1337i, - * => 1337u, + * => 1337u, }; assert(y is uint); }; diff --git a/tests/33-yield.ha b/tests/33-yield.ha @@ -0,0 +1,25 @@ +fn basics() void = { + let x = { + yield 10; + }; + let y = :outer { + if (true) { + yield :outer, 20; + }; + abort(); + }; + assert(x == 10); + assert(y == 20); +}; + +fn cast_lowering() void = { + let x: (int | void) = { + yield 10; + }; + assert(x as int == 10); +}; + +export fn main() void = { + basics(); + cast_lowering(); +}; diff --git a/tests/configure b/tests/configure @@ -35,7 +35,8 @@ tests() { 28-insert \ 29-unarithm \ 31-postfix \ - 32-copy + 32-copy \ + 33-yield do cat <<EOF tests/$t: libhart.a tests/$t.ha