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:
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