commit 028fd82fb5d9f1bcf9fb7eef42d651bd6906cd8a
parent 8796dcfafea729c7aa2f1f05975a8cc28d66768e
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 23 Jan 2021 16:41:35 -0500
Add match test
Diffstat:
4 files changed, 58 insertions(+), 18 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -887,34 +887,34 @@ check_expr_match(struct context *ctx,
_case = *next = xcalloc(1, sizeof(struct match_case));
next = &_case->next;
- const struct type *ctype = type_store_lookup_atype(
- ctx->store, acase->type);
+ const struct type *ctype = NULL;
+ if (acase->type) {
+ ctype = type_store_lookup_atype(ctx->store, acase->type);
- // TODO: Figure out alias semantics properly
- if (is_ptr) {
+ // TODO: Figure out alias semantics properly
switch (ctype->storage) {
case TYPE_STORAGE_POINTER:
+ expect(&acase->type->loc, is_ptr,
+ "Not matching on pointer type");
expect(&acase->type->loc,
type->pointer.referent == ctype->pointer.referent,
"Match case of incompatible pointer type");
break;
case TYPE_STORAGE_NULL:
- // No additional tests required
+ expect(&acase->type->loc, is_ptr,
+ "Not matching on pointer type");
break;
- default:
- expect(&acase->type->loc, false,
- "Invalid type for match case");
- break;
- }
- } else {
- bool valid = false;
- switch (ctype->storage) {
case TYPE_STORAGE_TAGGED_UNION:
+ expect(&acase->type->loc, !is_ptr,
+ "Not matching on tagged union type");
expect(&acase->type->loc, type_is_assignable(
ctx->store, type, ctype),
"Invalid type for match case");
break;
default:
+ expect(&acase->type->loc, !is_ptr,
+ "Not matching on tagged union type");
+ bool valid = false;
for (const struct type_tagged_union *tu = &type->tagged;
tu; tu = tu->next) {
if (tu->type == ctype) {
@@ -929,6 +929,7 @@ check_expr_match(struct context *ctx,
}
if (acase->name) {
+ assert(ctype);
struct identifier ident = {
.name = acase->name,
};
@@ -940,7 +941,7 @@ check_expr_match(struct context *ctx,
_case->value = xcalloc(1, sizeof(struct expression));
_case->type = ctype;
- check_expression(ctx, acase->value, _case->value, type);
+ check_expression(ctx, acase->value, _case->value, NULL);
if (acase->name) {
scope_pop(&ctx->scope, TR_CHECK);
diff --git a/src/gen.c b/src/gen.c
@@ -1397,10 +1397,11 @@ gen_expr_match(struct gen_context *ctx,
const struct type *mtype = expr->match.value->result;
struct qbe_value mval = {0}, tag = {0}, match = {0}, temp = {0};
- gen_temp(ctx, &mval, qtype_for_type(ctx, mtype, false), "match.%d");
- gen_temp(ctx, &temp, &qbe_word, "temp.%d");
- qval_address(&mval);
+ // Kill me
+ alloc_temp(ctx, &mval, mtype, "match.%d");
+ qval_deref(&mval);
gen_expression(ctx, expr->match.value, &mval);
+ gen_temp(ctx, &temp, &qbe_word, "temp.%d");
gen_temp(ctx, &tag, &qbe_word, "tag.%d");
pushi(ctx->current, &tag, Q_LOADUW, &mval, NULL);
diff --git a/tests/18-match.ha b/tests/18-match.ha
@@ -0,0 +1,37 @@
+fn tagged() void = {
+ let cases: [](int | uint | str) = [10, 10u, "hello"];
+ let expected = [1z, 2z, 5z];
+ for (let i = 0z; i < len(cases); i += 1z) {
+ let y: size = match (cases[i]) {
+ int => 1z,
+ uint => 2z,
+ s: str => len(s),
+ };
+ assert(y == expected[i]);
+ };
+};
+
+fn termination() void = {
+ let x: (int | uint | str) = 1337;
+ let y: int = match (x) {
+ int => 42,
+ uint => abort(),
+ str => abort(),
+ };
+ assert(y == 42);
+};
+
+fn default() void = {
+ let x: (int | uint | str) = 1337u;
+ let y: int = match (x) {
+ int => 42,
+ * => 24,
+ };
+ assert(y == 24);
+};
+
+export fn main() void = {
+ tagged();
+ termination();
+ default();
+};
diff --git a/tests/configure b/tests/configure
@@ -20,7 +20,8 @@ tests() {
14-switch \
15-enums \
16-defer \
- 17-alloc
+ 17-alloc \
+ 18-match
do
cat <<EOF
tests/$t: libhart.a tests/$t.ha