commit c9ddb0c6c63dc6d77a445ef1599c2f3c1d982115
parent aaee24a6426cac9490712aefe03221bbf6813e8d
Author: Drew DeVault <sir@cmpwn.com>
Date: Tue, 2 Feb 2021 20:08:15 -0500
gen: implement match against tagged subset
Diffstat:
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/gen.c b/src/gen.c
@@ -1521,6 +1521,27 @@ gen_recursive_match_tests(struct gen_context *ctx, const struct type *mtype,
}
static void
+gen_match_tagged_subset(struct gen_context *ctx,
+ struct qbe_value *tbranch, struct qbe_value *fbranch,
+ struct qbe_value *tag, struct match_case *_case)
+{
+ struct qbe_value temp = {0}, match = {0};
+ gen_temp(ctx, &temp, &qbe_word, "temp.%d");
+ const struct type_tagged_union *tu = &type_dealias(_case->type)->tagged;
+ while (tu) {
+ struct qbe_statement nlabel = {0};
+ struct qbe_value nbranch = {0};
+ nbranch.kind = QV_LABEL;
+ nbranch.name = strdup(genl(&nlabel, &ctx->id, "match.subtype.%d"));
+ constw(&match, tu->type->id);
+ pushi(ctx->current, &temp, Q_CEQW, &match, tag, NULL);
+ pushi(ctx->current, NULL, Q_JNZ, &temp, tbranch, &nbranch, NULL);
+ push(&ctx->current->body, &nlabel);
+ tu = tu->next;
+ }
+}
+
+static void
gen_match_tagged(struct gen_context *ctx,
const struct expression *expr,
const struct qbe_value *out)
@@ -1566,7 +1587,8 @@ gen_match_tagged(struct gen_context *ctx,
// tag, rather than advancing it to the value area,
// before initializing a binding for it.
reinterpret = true;
- assert(0); // TODO
+ gen_match_tagged_subset(ctx, &tbranch,
+ &fbranch, &tag, _case);
} else {
gen_recursive_match_tests(ctx, mtype,
&fbranch, &tag, &mval, _case);
diff --git a/tests/18-match.ha b/tests/18-match.ha
@@ -160,6 +160,27 @@ fn transitivity() void = {
assert(visit);
};
+type signed = (i8 | i16 | i32 | i64 | int);
+type unsigned = (u8 | u16 | u32 | u64 | uint | size);
+type integer = (...signed | ...unsigned);
+
+export fn numeric() void = {
+ // Real-world test
+ let visit = true;
+ let x: integer = 1337;
+ match (x) {
+ s: signed => match (s) {
+ i: int => {
+ visit = true;
+ assert(i == 1337);
+ },
+ * => abort(),
+ },
+ u: unsigned => abort(),
+ };
+ assert(visit);
+};
+
export fn main() void = {
tagged();
termination();
@@ -169,5 +190,6 @@ export fn main() void = {
tagged_result();
implicit_cast();
transitivity();
+ numeric();
// TODO: Test exhaustiveness and dupe detection
};