commit 8aa724d3d94bcd6f9fdc68934f8a1da97e3b5480
parent 1077f85ed77bcfcd98d50281f37fb7e8f61e29fa
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 6 Aug 2021 14:58:14 +0200
gen: implement casting from tagged unions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -544,8 +544,6 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
return out;
}
- assert(type_dealias(from)->storage != STORAGE_TAGGED); // TODO
-
if (type_dealias(to)->storage == type_dealias(from)->storage
&& to->size == from->size) {
struct gen_value value = gen_expr(ctx, expr->cast.value);
@@ -554,13 +552,28 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
}
// Special cases
+ if (type_dealias(from)->storage == STORAGE_TAGGED) {
+ // Cast from tagged union
+ struct gen_value value = gen_expr(ctx, expr->cast.value);
+ struct qbe_value base = mkcopy(ctx, &value, ".%d");
+ struct qbe_value align = constl(from->align);
+ pushi(ctx->current, &base, Q_ADD, &base, &align, NULL);
+ struct gen_value storage = (struct gen_value){
+ .kind = GV_TEMP,
+ .type = to,
+ .name = base.name,
+ };
+ return gen_load(ctx, storage);
+ }
switch (type_dealias(to)->storage) {
case STORAGE_POINTER:
if (type_dealias(from)->storage == STORAGE_SLICE) {
+ // Cast slice to pointer
assert(0); // TODO
}
break;
case STORAGE_VOID:
+ // Cast to void
gen_expr(ctx, expr->cast.value); // Side-effects
return gv_void;
default: break;
diff --git a/tests/910-tagged.ha b/tests/910-tagged.ha
@@ -63,8 +63,16 @@ fn subsetcast() void = {
assert(p.data.i == 1337);
};
+fn castout() void = {
+ let x: (int | void) = 1337;
+ let y = x: int;
+ assert(y == 1337);
+ // XXX: We can probably expand this
+};
+
export fn main() int = {
membercast();
subsetcast();
+ castout();
return 0;
};