bugfix: numerous bugs with new type kind
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 22 May 2023 14:54:29 +0000 (09:54 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 22 May 2023 14:54:29 +0000 (09:54 -0500)
compiler/src/astnodes.c
compiler/src/checker.c
compiler/src/parser.c
compiler/src/symres.c
compiler/src/types.c
compiler/src/utils.c
compiler/src/wasm_emit.c
tests/tagged_unions.onyx

index 213650e9e53ea01c3985bea9139216d70c8efa42..1055ddad3422d40b22d36ea26938ea7be3be407f 100644 (file)
@@ -1239,7 +1239,11 @@ b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
         return 0;
     }
 
-
+    if (from->kind == Type_Kind_Union && to->kind == Type_Kind_Enum) {
+        if (from->Union.tag_type->id == to->id) {
+            return 1;
+        }
+    }
 
     if (from->kind == Type_Kind_Enum) from = from->Enum.backing;
     if (to->kind == Type_Kind_Enum) to = to->Enum.backing;
index 4f5a6cc4db9e0f365707cd0c79d875f5777bd325..fe492897b9956e9b431fcaa78f20d132cd08f02f 100644 (file)
@@ -3641,6 +3641,8 @@ void check_entity(Entity* ent) {
         case Entity_Type_Type_Alias:
             if (ent->type_alias->kind == Ast_Kind_Struct_Type)
                 cs = check_struct((AstStructType *) ent->type_alias);
+            else if (ent->type_alias->kind == Ast_Kind_Union_Type)
+                cs = check_union((AstUnionType *) ent->type_alias);
             else
                 cs = check_type(&ent->type_alias);
             break;
index 358083ae5ecb896082b44e834cf7758d17972e10..8ad16fb6b2ae6a468a0090271f9be35cf831e293 100644 (file)
@@ -2171,7 +2171,10 @@ static AstStructType* parse_struct(OnyxParser* parser) {
     while (parser->curr->type == '#') {
         if (parser->hit_unexpected_token) return NULL;
 
-        if (parse_possible_directive(parser, "union")) s_node->is_union = 1;
+        if (next_tokens_are(parser, 2, '#', Token_Type_Keyword_Union)) {
+            consume_tokens(parser, 2);
+            s_node->is_union = 1;
+        }
 
         else if (parse_possible_directive(parser, "pack")) s_node->is_packed = 1;
 
index 50b39221e14075eb7862c7e767c20460aa292c66..086cc23a6805abc511da5714e46897e09c890226 100644 (file)
@@ -365,7 +365,8 @@ static SymresStatus symres_field_access(AstFieldAccess** fa) {
     if (expr->kind == Ast_Kind_Struct_Type ||
         expr->kind == Ast_Kind_Poly_Struct_Type ||
         expr->kind == Ast_Kind_Enum_Type ||
-        expr->kind == Ast_Kind_Type_Raw_Alias) {
+        expr->kind == Ast_Kind_Type_Raw_Alias ||
+        expr->kind == Ast_Kind_Union_Type) {
 
         force_a_lookup = 1;
     }
index 6b92c7c83591bb1e05552296864d41fbb2c14000..cd2a4082aad8535753e62c23a3a055548cd24967 100644 (file)
@@ -694,6 +694,8 @@ static Type* type_build_from_ast_inner(bh_allocator alloc, AstType* type_node, b
                 u_type = union_->pending_type;
             }
 
+            union_->pending_type_is_valid = 1;
+
             //
             // All variants need to have type know.
             bh_arr_each(AstUnionVariant *, pvariant, union_->variants) {
index 3bee7b734d62bc4d19b7795e1ca6ec169c2fd82d..70d3eb6ad08e5b27bc63576b3deba3ac2fd70522 100644 (file)
@@ -330,6 +330,18 @@ all_types_peeled_off:
             return result;
         }
 
+        case Ast_Kind_Union_Type: {
+            AstUnionType* utype = (AstUnionType *) node;
+            if (utype->utcache != NULL) {
+                //
+                // nocheckin Should this be hard coded?
+                if (!strcmp(symbol, "tag_enum")) {
+                    return (AstNode *) utype->utcache->Union.tag_type->ast_type;
+                }
+            }
+            break;
+        }
+
         case Ast_Kind_Poly_Struct_Type: {
             AstPolyStructType* stype = ((AstPolyStructType *) node);
             return symbol_raw_resolve(stype->scope, symbol);
index a42c15e9001f564062dd75cbf52d7c2f503cdb9e..2ec076f19a15922f6904450e9ce9299778e3290a 100644 (file)
@@ -983,24 +983,29 @@ EMIT_FUNC(store_instruction, Type* type, u32 offset) {
     i32 store_size  = type_size_of(type);
     i32 is_basic    = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer || type->kind == Type_Kind_MultiPointer;
 
-    if (is_basic && (type->Basic.flags & Basic_Flag_Pointer)) {
+    if (!is_basic) {
+        onyx_report_error((OnyxFilePos) { 0 }, Error_Critical,
+            "Failed to generate store instruction for type '%s'. (compiler bug)",
+            type_get_name(type));
+    }
+
+    if (type->Basic.flags & Basic_Flag_Pointer) {
         WID(NULL, WI_I32_STORE, ((WasmInstructionData) { 2, offset }));
-    } else if (is_basic && ((type->Basic.flags & Basic_Flag_Integer)
-                         || (type->Basic.flags & Basic_Flag_Boolean)
-                         || (type->Basic.flags & Basic_Flag_Type_Index))) {
+    } else if ((type->Basic.flags & Basic_Flag_Integer)
+               || (type->Basic.flags & Basic_Flag_Boolean)
+               || (type->Basic.flags & Basic_Flag_Type_Index)) {
         if      (store_size == 1)   WID(NULL, WI_I32_STORE_8,  ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 2)   WID(NULL, WI_I32_STORE_16, ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 4)   WID(NULL, WI_I32_STORE,    ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 8)   WID(NULL, WI_I64_STORE,    ((WasmInstructionData) { alignment, offset }));
-    } else if (is_basic && (type->Basic.flags & Basic_Flag_Float)) {
+    } else if (type->Basic.flags & Basic_Flag_Float) {
         if      (store_size == 4)   WID(NULL, WI_F32_STORE, ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 8)   WID(NULL, WI_F64_STORE, ((WasmInstructionData) { alignment, offset }));
-    } else if (is_basic && (type->Basic.flags & Basic_Flag_SIMD)) {
+    } else if (type->Basic.flags & Basic_Flag_SIMD) {
         WID(NULL, WI_V128_STORE, ((WasmInstructionData) { alignment, offset }));
-    } else {
-        onyx_report_error((OnyxFilePos) { 0 }, Error_Critical,
-            "Failed to generate store instruction for type '%s'.",
-            type_get_name(type));
+    } else if (type->Basic.kind == Basic_Kind_Void) {
+        // Do nothing, but drop the destination pointer.
+        WI(NULL, WI_DROP);
     }
 
     *pcode = code;
@@ -3794,6 +3799,14 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
         return;
     }
 
+    if (from->kind == Type_Kind_Union) {
+        // This should be check in the checker that are only casting
+        // to the union's tag_type.
+        emit_load_instruction(mod, &code, from->Union.tag_type, 0);
+        *pcode = code;
+        return;
+    }
+
     if (to->kind == Type_Kind_Basic && from->kind == Type_Kind_Function) {
         WI(NULL, WI_DROP);
         WI(NULL, WI_DROP);
index 95a13dcc622d893207ba9378f9cf0d1f8f0abd50..5bfb2fa484c32b7a54c9a098b3de00555abced25 100644 (file)
@@ -4,58 +4,74 @@ use core {*}
 SimpleUnion :: union {
     a: i32;
     b: struct {
-        c, d: str;
+        c: str;
     };
+
+    empty: void;
+    large: i64;
+}
+
+call_test :: (u_: SimpleUnion) {
+    u := u_;
+    __byte_dump(&u, sizeof typeof u);
+
+    switch cast(SimpleUnion.tag_enum) u {
+        case .a do println("It was a!");
+        case .b do println("It was B!");
+        case .empty do println("It was EMPTY!");
+        case .large do println("It was a large number!");
+    }
 }
 
 simple_test :: () {
-    u := SimpleUnion.{ a = 123 };
+    u := SimpleUnion.{ b = .{ "asdf" } };
+    u  = .{ a = 123 };
+    u  = .{ empty = .{} };
+    u  = .{ large = 0x0123456789abcdef };
 
-    println(sizeof str);
-    println(sizeof str * 2 + sizeof i32);
+    println(cast(SimpleUnion.tag_enum) u);
 
-    __byte_dump(&u, sizeof typeof u);
-    println(u.a);
+    call_test(u);
 }
 
-main :: () {simple_test();}
+main :: () {simple_test();} //link_test();}
 
+Link :: union {
+    End: void;
+    Next: struct {
+        data: i32;
+        next: &Link;
+    }
+}
+
+/*
+print_links :: (l: Link) {
+    walker := l;
+    while true {
+        switch walker {
+            case Link.End do break;
+            case Link.Next => &next {
+                printf("{} ", next.data);
+                walker = next.next;
+            }
+        }
+    }
+}
+
+link_test :: () {
+    l := Link.{
+        Next = .{
+            data = 123,
+            next = &Link.{
+                End = .{}
+            }
+        }
+    };
+    
+    print_links(l);
+}
+*/
 
-// Link :: union {
-//     End: void;
-//     Next: struct {
-//         data: i32;
-//         next: &Link;
-//     }
-// }
-// 
-// print_links :: (l: Link) {
-//     walker := l;
-//     while true {
-//         switch walker {
-//             case .End do break;
-//             case .Next {
-//                 next: struct {data: i32; next: rawptr};
-//                 printf("{} ", next.data);
-//                 walker = next.next;
-//             }
-//         }
-//     }
-// }
-// 
-// link_test :: () {
-//     l := Link.{
-//         Next = .{
-//             data = 123,
-//             next = &Link.{
-//                 End = .{}
-//             }
-//         }
-//     };
-//     
-//     print_links(l);
-// }
-// 
 // main :: () { link_test(); }
 
 // Optional :: union (T: type_expr) {