added: switching over pointer to union
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 24 May 2023 00:03:46 +0000 (19:03 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 24 May 2023 00:03:46 +0000 (19:03 -0500)
CHANGELOG
compiler/src/checker.c
compiler/src/wasm_emit.c
core/container/optional.onyx

index a140f9ccc38377004c9d1d70103e2a5caebbc50c..582e2715f667c79c67c776bcb7742bf74ba397c8 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@ Release v0.1.2
 Unreleased
 
 Additions:
+* Tagged unions (`union` type)
 * String literals can have unicode code points.
     - '\uXXXX' for small code points (less than U+FFFF)
     - '\UXXXXXX' for large code points
@@ -14,6 +15,8 @@ Additions:
 Removals:
 
 Changes:
+* `Optional` is now a tagged-union
+* `Result` is now a tagged-union
 * `iter.single` can take a `dispose` function, which is called on close of the
     iterator, with the single value yielded.
 * `io.write_escaped_str` supports escaping "\\" now.
index c6318ad2038d83c1d3ddf7c6acba8c62dc51603c..c590c122d600c7046357decb42728410ff7bc63c 100644 (file)
@@ -440,7 +440,8 @@ CheckStatus check_switch(AstSwitch* switchnode) {
         if (!type_is_integer(switchnode->expr->type) && switchnode->expr->type->kind != Type_Kind_Enum) {
             switchnode->switch_kind = Switch_Kind_Use_Equals;
         }
-        if (switchnode->expr->type->kind == Type_Kind_Union) {
+        if (switchnode->expr->type->kind == Type_Kind_Union
+            || (switchnode->expr->type->kind == Type_Kind_Pointer && switchnode->expr->type->Pointer.elem->kind == Type_Kind_Union)) {
             switchnode->switch_kind = Switch_Kind_Union;
         }
 
@@ -488,7 +489,8 @@ CheckStatus check_switch(AstSwitch* switchnode) {
         }
 
         if (sc->capture && switchnode->switch_kind != Switch_Kind_Union) {
-            ERROR(sc->capture->token->pos, "Captures in switch cases are only allowed when switching over a union type.");
+            ERROR_(sc->capture->token->pos, "Captures in switch cases are only allowed when switching over a union type. Switching over '%s' here.",
+                    type_get_name(switchnode->expr->type));
         }
 
         if (sc->flags & Ast_Flag_Has_Been_Checked) goto check_switch_case_block;
@@ -522,16 +524,21 @@ CheckStatus check_switch(AstSwitch* switchnode) {
             }
 
             if (switchnode->switch_kind == Switch_Kind_Union) {
-                TYPE_CHECK(value, resolved_expr_type->Union.tag_type) {
+                Type *union_expr_type = resolved_expr_type;
+                if (union_expr_type->kind == Type_Kind_Pointer) {
+                    union_expr_type = union_expr_type->Pointer.elem;
+                }
+
+                TYPE_CHECK(value, union_expr_type->Union.tag_type) {
                     OnyxToken* tkn = sc->block->token;
                     if ((*value)->token) tkn = (*value)->token;
 
                     ERROR_(tkn->pos, "'%b' is not a variant of '%s'.",
-                        (*value)->token->text, (*value)->token->length, type_get_name(resolved_expr_type));
+                        (*value)->token->text, (*value)->token->length, type_get_name(union_expr_type));
                 }
 
                 // nocheckin Explain the -1
-                UnionVariant *union_variant = resolved_expr_type->Union.variants_ordered[get_expression_integer_value(*value, NULL) - 1];
+                UnionVariant *union_variant = union_expr_type->Union.variants_ordered[get_expression_integer_value(*value, NULL) - 1];
                 if (sc->capture) {
                     if (sc->capture_is_by_pointer) {
                         sc->capture->type = type_make_pointer(context.ast_alloc, union_variant->type);
index 5de1db7c31a4c270a58fca12d5c1e86c7f0fe8ee..4c6b1124c4e05ad3ec1b2314c558e0f9e7d9f391 100644 (file)
@@ -1656,10 +1656,15 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
             emit_expression(mod, &code, switch_node->expr);
 
             if (switch_node->switch_kind == Switch_Kind_Union) {
-                assert(switch_node->expr->type->kind == Type_Kind_Union);
+                Type *union_expr_type = switch_node->expr->type;
+                if (union_expr_type->kind == Type_Kind_Pointer) {
+                    union_expr_type = union_expr_type->Pointer.elem;
+                }
+                assert(union_expr_type->kind == Type_Kind_Union);
+
                 union_capture_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
                 WIL(NULL, WI_LOCAL_TEE, union_capture_idx);
-                emit_load_instruction(mod, &code, switch_node->expr->type->Union.tag_type, 0);
+                emit_load_instruction(mod, &code, union_expr_type->Union.tag_type, 0);
             }
 
             if (switch_node->min_case != 0) {
@@ -1702,11 +1707,16 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
         if (sc->capture) {
             assert(union_capture_idx != 0);
 
+            Type *union_expr_type = switch_node->expr->type;
+            if (union_expr_type->kind == Type_Kind_Pointer) {
+                union_expr_type = union_expr_type->Pointer.elem;
+            }
+
             if (sc->capture_is_by_pointer) {
                 u64 capture_pointer_local = emit_local_allocation(mod, &code, (AstTyped *) sc->capture);
 
                 WIL(NULL, WI_LOCAL_GET, union_capture_idx);
-                WIL(NULL, WI_PTR_CONST, switch_node->expr->type->Union.alignment);
+                WIL(NULL, WI_PTR_CONST, union_expr_type->Union.alignment);
                 WI(NULL, WI_PTR_ADD);
 
                 WIL(NULL, WI_LOCAL_SET, capture_pointer_local);
@@ -1719,7 +1729,7 @@ EMIT_FUNC(switch, AstSwitch* switch_node) {
                 emit_location(mod, &code, (AstTyped *) sc->capture);
 
                 WIL(NULL, WI_LOCAL_GET, union_capture_idx);
-                WIL(NULL, WI_PTR_CONST, switch_node->expr->type->Union.alignment);
+                WIL(NULL, WI_PTR_CONST, union_expr_type->Union.alignment);
                 WI(NULL, WI_PTR_ADD);
                 
                 WIL(NULL, WI_I32_CONST, type_size_of(sc->capture->type));
index f049a70b1a9a761897a8728d57a705acb0e5400f..ca40195d95a8b0885852a871e83a10ac14b3289c 100644 (file)
@@ -109,7 +109,7 @@ use core
         If not, an assertion is thrown and the context's assert handler must
         take care of it.
     """
-    unwrap_ptr :: (o: ?$T) -> &T {
+    unwrap_ptr :: (o: ?$T) -> &T {
         switch o {
             case .Some => &v do return v;
             case #default {