commit e976c86b2efc493c69053ff13cb68d124503d76c
parent e9acfa8ee777ea3290553af54079c79c8ff4e62e
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 26 Sep 2021 10:41:31 +0200
gen: implement tagged union reflection
Diffstat:
2 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -3702,6 +3702,48 @@ gen_type_info(struct gen_context *ctx,
item->value = constl(len);
break;
case STORAGE_TAGGED:
+ *repr_name = "tagged";
+ item->value = constw(type_hash(&repr));
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ item->type = QD_ZEROED;
+ item->zeroed = 4;
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+
+ def = xcalloc(1, sizeof(struct qbe_def));
+ def->name = gen_name(ctx, "sldata.%d");
+ def->kind = Q_DATA;
+ subitem = &def->data.items;
+ for (const struct type_tagged_union *tu = &type->tagged;
+ tu; tu = tu->next) {
+ ref = mktyperef(ctx, tu->type);
+ subitem->type = QD_VALUE;
+ subitem->value.kind = QV_GLOBAL;
+ subitem->value.type = &qbe_long;
+ subitem->value.name = ref.name;
+ if (tu->next) {
+ subitem->next = xcalloc(1, sizeof(struct qbe_data_item));
+ subitem = subitem->next;
+ }
+ ++len;
+ }
+ qbe_append_def(ctx->out, def);
+
+ item->type = QD_VALUE;
+ item->value.kind = QV_GLOBAL;
+ item->value.type = &qbe_long;
+ item->value.name = strdup(def->name);
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+ item->type = QD_VALUE;
+ item->value = constl(len);
+ item->next = xcalloc(1, sizeof(struct qbe_data_item));
+ item = item->next;
+ item->type = QD_VALUE;
+ item->value = constl(len);
+ break;
case STORAGE_TUPLE:
// XXX: Temporary code to make sure code in the wild builds
// while we flesh out these types
diff --git a/tests/34-reflect.ha b/tests/34-reflect.ha
@@ -166,6 +166,32 @@ fn struct_union() void = {
assert(su.fields[2].offs == 8);
};
+fn tagged() void = {
+ let ty = types::reflect(type((int | uint | void)));
+ assert(ty.sz == size(uint) * 2);
+ assert(ty.al == size(uint));
+ let ta = ty.repr as types::tagged;
+ assert(len(ta) == 3);
+ // The order of fields in a tagged union type is not consistent with
+ // their AST ordering, so we don't expect specific types at specific
+ // indicies. It is consistently ordered (based on type ID), but the type
+ // IDs change whenever the ABI changes and I don't feel like updating
+ // this every time.
+ let _i = false, _u = false, _v = false;
+ for (let i = 0z; i < len(ta); i += 1) {
+ if (ta[i] == type(int)) {
+ _i = true;
+ };
+ if (ta[i] == type(uint)) {
+ _u = true;
+ };
+ if (ta[i] == type(void)) {
+ _v = true;
+ };
+ };
+ assert(_i && _u && _v);
+};
+
export fn main() void = {
builtins();
aliases();
@@ -175,4 +201,5 @@ export fn main() void = {
pointers();
functions();
struct_union();
+ tagged();
};