types are even more first class
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 23 Jun 2021 02:40:17 +0000 (21:40 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 23 Jun 2021 02:40:17 +0000 (21:40 -0500)
bin/onyx
core/type_info.onyx
include/onyxastnodes.h
src/onyxastnodes.c
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index 14477b46c57ff62eda8ed1cc8b8bb7a76b57326a..2bcf731c7ba9e5cae9112a2324d8730a6de236de 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index ea094e7e413a7e4d84e39d5411c31971d6e2da78..c62ab36bc206a6ec2d1d888d792b8ebabb220204 100644 (file)
@@ -3,7 +3,6 @@
 
 package core.type_info
 
-Type_Index :: #type u32
 type_table : [] ^Type_Info;
 
 Type_Info :: struct {
@@ -68,14 +67,14 @@ Type_Info_Pointer :: struct {
     use base : Type_Info;
 
     @Rename
-    to: Type_Index;
+    to: type_expr;
 }
 
 Type_Info_Function :: struct {
     use base : Type_Info;
 
-    return_type:        Type_Index;
-    parameter_types: [] Type_Index;
+    return_type:        type_expr;
+    parameter_types: [] type_expr;
 
     is_variadic: bool;
 }
@@ -84,7 +83,7 @@ Type_Info_Array :: struct {
     use base : Type_Info;
 
     @Rename
-    of: Type_Index;
+    of: type_expr;
     count: u32;
 }
 
@@ -92,21 +91,21 @@ Type_Info_Slice :: struct {
     use base : Type_Info;
 
     @Rename
-    of: Type_Index;
+    of: type_expr;
 }
 
 Type_Info_Dynamic_Array :: struct {
     use base : Type_Info;
 
     @Rename
-    of: Type_Index;
+    of: type_expr;
 }
 
 Type_Info_Variadic_Argument :: struct {
     use base : Type_Info;
 
     @Rename
-    of: Type_Index;
+    of: type_expr;
 }
 
 Type_Info_Enum :: struct {
@@ -118,7 +117,7 @@ Type_Info_Enum :: struct {
     }
 
     // This is first for better alignment
-    backing_type: Type_Index;
+    backing_type: type_expr;
     name: str;
     members: [] Member;
 
@@ -131,7 +130,7 @@ Type_Info_Struct :: struct {
     Member :: struct {
         name: str;
         offset: u32;
-        type_index: Type_Index;
+        type_index: type_expr;
 
         used: bool;
         has_default: bool;
@@ -144,11 +143,11 @@ Type_Info_Struct :: struct {
 Type_Info_Compound :: struct {
     use base : Type_Info;
 
-    components : [] Type_Index;
+    components : [] type_expr;
 }
 
-get_type_info :: (t: Type_Index) -> ^Type_Info {
-    if t < 0 || t >= type_table.count do return null;
+get_type_info :: (t: type_expr) -> ^Type_Info {
+    if t < ~~0 || t >= ~~type_table.count do return null;
 
-    return type_table[t];
+    return type_table[cast(i32) t];
 }
\ No newline at end of file
index a762abba490f6dcb27f327d02c4b0070eee1fbe2..fb6c3943294b2e325fc5cbb2950f30d9214e23c1 100644 (file)
@@ -1178,6 +1178,7 @@ extern AstBasicType basic_type_u64;
 extern AstBasicType basic_type_f32;
 extern AstBasicType basic_type_f64;
 extern AstBasicType basic_type_rawptr;
+extern AstBasicType basic_type_type_expr; // :TypeExprHack
 
 extern AstBasicType basic_type_int_unsized;
 extern AstBasicType basic_type_float_unsized;
@@ -1191,9 +1192,6 @@ extern AstBasicType basic_type_f64x2;
 extern AstBasicType basic_type_v128;
 
 
-// :TypeExprHack
-extern AstNode type_expr_symbol;
-
 extern OnyxToken builtin_package_token;
 extern AstNumLit builtin_heap_start;
 extern AstGlobal builtin_stack_top;
index abb5752a17028e49a0adc2666371112c7c266005..15793918da613cad34345abec16ba62ad2eae2b2 100644 (file)
@@ -430,7 +430,7 @@ b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) {
     if (type == NULL) return 0;
     if (node == NULL) return 0;
 
-    if (node_is_type((AstNode *) node)) return 0;
+    // if (node_is_type((AstNode *) node)) return 0;
 
     if (node->kind == Ast_Kind_Struct_Literal && node->type_node == NULL) {
         if (type->kind == Type_Kind_VarArgs) type = type->VarArgs.ptr_to_data->Pointer.elem;
@@ -531,7 +531,7 @@ Type* resolve_expression_type(AstTyped* node) {
     }
 
     if (node_is_type((AstNode *) node)) {
-        return NULL;
+        return &basic_types[Basic_Kind_Type_Index];
     }
 
     if (node->type == NULL)
@@ -571,21 +571,27 @@ i64 get_expression_integer_value(AstTyped* node) {
         return ((AstAlignOf *) node)->alignment;
     }
 
+    if (node_is_type((AstNode*) node)) {
+        Type* type = type_build_from_ast(context.ast_alloc, (AstType *) node);
+        return type->id;
+    }
+
     return 0;
 }
 
-static const b32 cast_legality[][11] = {
-    /* I8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
-    /* U8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
-    /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
-    /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
-    /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
-    /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
-    /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
-    /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1 },
+static const b32 cast_legality[][12] = {
+    /* I8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+    /* U8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+    /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+    /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+    /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
+    /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
+    /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0 },
+    /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0 },
+    /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0 },
+    /* TYP */ { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1,}
 };
 
 b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
@@ -650,6 +656,9 @@ b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
     else if (from->Basic.flags & Basic_Flag_Boolean) {
         fromidx = 0;
     }
+    else if (from->Basic.flags & Basic_Flag_Type_Index) {
+        fromidx = 11;
+    }
 
     if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) {
         toidx = 10;
@@ -666,6 +675,9 @@ b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
     else if (to->Basic.flags & Basic_Flag_Boolean) {
         toidx = 0;
     }
+    else if (to->Basic.flags & Basic_Flag_Type_Index) {
+        toidx = 11;
+    }
 
     if (fromidx != -1 && toidx != -1) {
         if (!cast_legality[fromidx][toidx]) {
index 745209a508e0a95c7a2622e5215aed35a0940027..d3282244ed1eb804f3ef8e8ad9f281ebf8113096 100644 (file)
@@ -3,19 +3,20 @@
 #include "onyxerrors.h"
 #include "onyxutils.h"
 
-AstBasicType basic_type_void   = { Ast_Kind_Basic_Type, 0, NULL, NULL, "void"  , NULL, NULL, &basic_types[Basic_Kind_Void]  };
-AstBasicType basic_type_bool   = { Ast_Kind_Basic_Type, 0, NULL, NULL, "bool"  , NULL, NULL, &basic_types[Basic_Kind_Bool]  };
-AstBasicType basic_type_i8     = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i8"    , NULL, NULL, &basic_types[Basic_Kind_I8]    };
-AstBasicType basic_type_u8     = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u8"    , NULL, NULL, &basic_types[Basic_Kind_U8]    };
-AstBasicType basic_type_i16    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i16"   , NULL, NULL, &basic_types[Basic_Kind_I16]   };
-AstBasicType basic_type_u16    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u16"   , NULL, NULL, &basic_types[Basic_Kind_U16]   };
-AstBasicType basic_type_i32    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i32"   , NULL, NULL, &basic_types[Basic_Kind_I32]   };
-AstBasicType basic_type_u32    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u32"   , NULL, NULL, &basic_types[Basic_Kind_U32]   };
-AstBasicType basic_type_i64    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i64"   , NULL, NULL, &basic_types[Basic_Kind_I64]   };
-AstBasicType basic_type_u64    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u64"   , NULL, NULL, &basic_types[Basic_Kind_U64]   };
-AstBasicType basic_type_f32    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "f32"   , NULL, NULL, &basic_types[Basic_Kind_F32]   };
-AstBasicType basic_type_f64    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "f64"   , NULL, NULL, &basic_types[Basic_Kind_F64]   };
-AstBasicType basic_type_rawptr = { Ast_Kind_Basic_Type, 0, NULL, NULL, "rawptr", NULL, NULL, &basic_types[Basic_Kind_Rawptr] };
+AstBasicType basic_type_void      = { Ast_Kind_Basic_Type, 0, NULL, NULL, "void"  ,    NULL, NULL, &basic_types[Basic_Kind_Void]  };
+AstBasicType basic_type_bool      = { Ast_Kind_Basic_Type, 0, NULL, NULL, "bool"  ,    NULL, NULL, &basic_types[Basic_Kind_Bool]  };
+AstBasicType basic_type_i8        = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i8"    ,    NULL, NULL, &basic_types[Basic_Kind_I8]    };
+AstBasicType basic_type_u8        = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u8"    ,    NULL, NULL, &basic_types[Basic_Kind_U8]    };
+AstBasicType basic_type_i16       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i16"   ,    NULL, NULL, &basic_types[Basic_Kind_I16]   };
+AstBasicType basic_type_u16       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u16"   ,    NULL, NULL, &basic_types[Basic_Kind_U16]   };
+AstBasicType basic_type_i32       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i32"   ,    NULL, NULL, &basic_types[Basic_Kind_I32]   };
+AstBasicType basic_type_u32       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u32"   ,    NULL, NULL, &basic_types[Basic_Kind_U32]   };
+AstBasicType basic_type_i64       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "i64"   ,    NULL, NULL, &basic_types[Basic_Kind_I64]   };
+AstBasicType basic_type_u64       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "u64"   ,    NULL, NULL, &basic_types[Basic_Kind_U64]   };
+AstBasicType basic_type_f32       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "f32"   ,    NULL, NULL, &basic_types[Basic_Kind_F32]   };
+AstBasicType basic_type_f64       = { Ast_Kind_Basic_Type, 0, NULL, NULL, "f64"   ,    NULL, NULL, &basic_types[Basic_Kind_F64]   };
+AstBasicType basic_type_rawptr    = { Ast_Kind_Basic_Type, 0, NULL, NULL, "rawptr",    NULL, NULL, &basic_types[Basic_Kind_Rawptr] };
+AstBasicType basic_type_type_expr = { Ast_Kind_Basic_Type, 0, NULL, NULL, "type_expr", NULL, NULL, &basic_types[Basic_Kind_Type_Index] };
 
 // NOTE: Types used for numeric literals
 AstBasicType basic_type_int_unsized   = { Ast_Kind_Basic_Type, 0, NULL, NULL, "unsized_int",   NULL, NULL, &basic_types[Basic_Kind_Int_Unsized] };
@@ -37,10 +38,6 @@ static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_to
 AstNumLit builtin_heap_start  = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
 AstGlobal builtin_stack_top   = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top,  &builtin_stack_top_token, NULL, NULL, (AstType *) &basic_type_rawptr, NULL };
 
-// :TypeExprHack
-static OnyxToken type_expr_token = { Token_Type_Symbol, 9, "type_expr", { 0 } };
-AstNode type_expr_symbol         = { Ast_Kind_Error, 0, &type_expr_token, NULL, NULL };
-
 AstType  *builtin_string_type;
 AstType  *builtin_range_type;
 Type     *builtin_range_type_type;
@@ -67,7 +64,7 @@ const BuiltinSymbol builtin_symbols[] = {
     { NULL, "f32",        (AstNode *) &basic_type_f32 },
     { NULL, "f64",        (AstNode *) &basic_type_f64 },
     { NULL, "rawptr",     (AstNode *) &basic_type_rawptr },
-    { NULL, "type_expr",  (AstNode *) &type_expr_symbol },
+    { NULL, "type_expr",  (AstNode *) &basic_type_type_expr },
 
     { "simd", "i8x16",    (AstNode *) &basic_type_i8x16 },
     { "simd", "i16x8",    (AstNode *) &basic_type_i16x8 },
index 9ff489ec08d68646ce7adf4c3e79d3900da13589..9f953de9d7945e61903f1c617972f94b774d9661 100644 (file)
@@ -286,10 +286,12 @@ CheckStatus check_switch(AstSwitch* switchnode) {
         return Check_Error;
     }
 
+    // LEAK if this has to be yielded
     bh_imap_init(&switchnode->case_map, global_heap_allocator, bh_arr_length(switchnode->cases) * 2);
 
     switchnode->min_case = 0xffffffffffffffff;
 
+    // Umm, this doesn't check the type of the case expression to the type of the expression
     bh_arr_each(AstSwitchCase, sc, switchnode->cases) {
         CHECK(block, sc->block);
 
@@ -297,10 +299,7 @@ CheckStatus check_switch(AstSwitch* switchnode) {
             CHECK(expression, value);
 
             // :UnaryFieldAccessIsGross
-            if ((*value)->kind == Ast_Kind_Unary_Field_Access) {
-                type_check_or_auto_cast(value, resolved_expr_type);
-            }
-
+            // if ((*value)->kind == Ast_Kind_Unary_Field_Access) {
             if ((*value)->kind == Ast_Kind_Range_Literal) {
                 AstRangeLiteral* rl = (AstRangeLiteral *) (*value);
                 resolve_expression_type(rl->low);
@@ -326,6 +325,25 @@ CheckStatus check_switch(AstSwitch* switchnode) {
                 continue;
             }
 
+            if (!type_check_or_auto_cast(value, resolved_expr_type)) {
+                OnyxToken* tkn = sc->block->token;
+                if ((*value)->token) tkn = (*value)->token;
+
+                onyx_report_error(tkn->pos, "Mismatched types in switch-case. Expected '%s', got '%s'.",
+                    type_get_name(resolved_expr_type), type_get_name((*value)->type));
+                
+                return Check_Error;
+            }
+
+            if (node_is_type((AstNode*) (*value))) {
+                Type* type = type_build_from_ast(context.ast_alloc, (AstType*) (*value));
+
+                if (add_case_to_switch_statement(switchnode, type->id, sc->block, sc->block->token->pos))
+                    return Check_Error;
+
+                continue;
+            }
+
             if ((*value)->kind == Ast_Kind_Enum_Value) {
                 (*value) = (AstTyped *) ((AstEnumValue *) (*value))->value;
             }
@@ -793,12 +811,12 @@ static b32 binary_op_is_allowed(BinaryOp operation, Type* type) {
 
     enum BasicFlag effective_flags = 0;
     switch (type->kind) {
-        case Type_Kind_Basic:   effective_flags = binop->type->Basic.flags; break;
-        case Type_Kind_Pointer: effective_flags = Basic_Flag_Pointer;       break;
-        case Type_Kind_Enum:    effective_flags = Basic_Flag_Integer;       break;
+        case Type_Kind_Basic:   effective_flags = type->Basic.flags;  break;
+        case Type_Kind_Pointer: effective_flags = Basic_Flag_Pointer; break;
+        case Type_Kind_Enum:    effective_flags = Basic_Flag_Integer; break;
     }
 
-    return (binop_allowed[binop->operation] & effective_flags) == 0;
+    return (binop_allowed[operation] & effective_flags) != 0;
 }
 
 CheckStatus check_binaryop_compare(AstBinaryOp** pbinop) {
@@ -1486,6 +1504,13 @@ CheckStatus check_align_of(AstAlignOf* ao) {
 CheckStatus check_expression(AstTyped** pexpr) {
     AstTyped* expr = *pexpr;
     if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) {
+        // This is to ensure that the type will exist when compiling. For example, a poly-call type
+        // would have to wait for the entity to pass through, which the code generation does not know
+        // about.
+        if (type_build_from_ast(context.ast_alloc, (AstType*) expr) == NULL) {
+            return Check_Yield_Macro;
+        }
+
         expr->type = &basic_types[Basic_Kind_Type_Index];
         return Check_Success;
     }
index e3ecd50333e6d583fe883c4df757f2b092bcdfe8..36fc57bf9f38cf2db3cb4669e8f459f758ee4b36 100644 (file)
@@ -36,7 +36,7 @@ Type basic_types[] = {
     { Type_Kind_Basic, 0, 0, (AstType *) &basic_type_f64x2, { Basic_Kind_F64X2,  Basic_Flag_SIMD,                        16, 16, "f64x2" } },
     { Type_Kind_Basic, 0, 0, (AstType *) &basic_type_v128,  { Basic_Kind_V128,   Basic_Flag_SIMD,                        16, 16, "v128"  } },
 
-    { Type_Kind_Basic, 0, 0, NULL,                          { Basic_Kind_Type_Index, Basic_Flag_Type_Index,              4,  4, "Type_Index" } },
+    { Type_Kind_Basic, 0, 0, NULL,                          { Basic_Kind_Type_Index, Basic_Flag_Type_Index,              4,  4, "type_expr" } },
 };
 
 // TODO: Document this!!
@@ -1092,7 +1092,8 @@ b32 type_is_small_integer(Type* type) {
 b32 type_is_integer(Type* type) {
     if (type->kind != Type_Kind_Basic) return 0;
 
-    return type->Basic.kind >= Basic_Kind_I8 && type->Basic.kind <= Basic_Kind_U64;
+    return (type->Basic.kind >= Basic_Kind_I8 && type->Basic.kind <= Basic_Kind_U64)
+        || type->Basic.kind == Basic_Kind_Type_Index;
 }
 
 b32 type_is_numeric(Type* type) {
index e737e804d61c97ebad3f2ee789b003a50b0f459b..5864662f73998c03b540701a939a11df1b0fdfc5 100644 (file)
@@ -686,7 +686,7 @@ static void solve_for_polymorphic_param_value(PolySolveResult* resolved, AstPoly
         value = ((AstArgument *) value)->value;
     }
 
-    if (param->type_expr == (AstType *) &type_expr_symbol) {
+    if (param->type_expr == (AstType *) &basic_type_type_expr) {
         if (!node_is_type((AstNode *) value)) {
             if (err_msg) *err_msg = "Expected type expression.";
             return;
@@ -1233,7 +1233,7 @@ AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstP
         sln->poly_sym = (AstNode *) &ps_type->poly_params[i];
         
         PolySolutionKind expected_kind = PSK_Undefined;
-        if ((AstNode *) ps_type->poly_params[i].type_node == &type_expr_symbol) {
+        if ((AstNode *) ps_type->poly_params[i].type_node == (AstNode *) &basic_type_type_expr) {
             expected_kind = PSK_Type;
         } else {
             expected_kind = PSK_Value;
index 2eac1ec92b45be22fcda318435dcc009cf357aa2..a8823798637d089340b15c3df861c881fd584ebd 100644 (file)
@@ -64,6 +64,7 @@ static WasmType onyx_type_to_wasm_type(Type* type) {
             if (basic->size == 8) return WASM_TYPE_FLOAT64;
         }
         if (basic->flags & Basic_Flag_SIMD) return WASM_TYPE_VAR128;
+        if (basic->flags & Basic_Flag_Type_Index) return WASM_TYPE_INT32;
         if (basic->size == 0) return WASM_TYPE_VOID;
     }
 
@@ -578,7 +579,9 @@ EMIT_FUNC(store_instruction, Type* type, u32 offset) {
 
     if (is_basic && (type->Basic.flags & Basic_Flag_Pointer)) {
         WID(WI_I32_STORE, ((WasmInstructionData) { 2, offset }));
-    } else if (is_basic && ((type->Basic.flags & Basic_Flag_Integer) || (type->Basic.flags & Basic_Flag_Boolean))) {
+    } else if (is_basic && ((type->Basic.flags & Basic_Flag_Integer)
+                         || (type->Basic.flags & Basic_Flag_Boolean)
+                         || (type->Basic.flags & Basic_Flag_Type_Index))) {
         if      (store_size == 1)   WID(WI_I32_STORE_8,  ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 2)   WID(WI_I32_STORE_16, ((WasmInstructionData) { alignment, offset }));
         else if (store_size == 4)   WID(WI_I32_STORE,    ((WasmInstructionData) { alignment, offset }));
@@ -628,7 +631,9 @@ EMIT_FUNC(load_instruction, Type* type, u32 offset) {
         instr = WI_I32_LOAD;
         alignment = 2;
     }
-    else if (is_basic && ((type->Basic.flags & Basic_Flag_Integer) || (type->Basic.flags & Basic_Flag_Boolean))) {
+    else if (is_basic && ((type->Basic.flags & Basic_Flag_Integer)
+                       || (type->Basic.flags & Basic_Flag_Boolean)
+                       || (type->Basic.flags & Basic_Flag_Type_Index))) {
         if      (load_size == 1) instr = WI_I32_LOAD_8_S;
         else if (load_size == 2) instr = WI_I32_LOAD_16_S;
         else if (load_size == 4) instr = WI_I32_LOAD;
@@ -2566,19 +2571,20 @@ EMIT_FUNC(expression, AstTyped* expr) {
     *pcode = code;
 }
 
-static const WasmInstructionType cast_map[][11] = {
+static const WasmInstructionType cast_map[][12] = {
     //          I8              U8                  I16                 U16                I32                 U32                I64                U64                F32                F64                PTR
-    /* I8  */ { WI_NOP,         WI_NOP,             WI_I32_EXTEND_8_S,  WI_NOP,            WI_I32_EXTEND_8_S,  WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE },
-    /* U8  */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE },
-    /* I16 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_I32_EXTEND_16_S, WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE },
-    /* U16 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE },
-    /* I32 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_F32_FROM_I32_S, WI_F64_FROM_I32_S, WI_NOP },
-    /* U32 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_F32_FROM_I32_U, WI_F64_FROM_I32_U, WI_NOP },
-    /* I64 */ { WI_NOP,         WI_I32_FROM_I64,    WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_NOP,            WI_NOP,            WI_F32_FROM_I64_S, WI_F64_FROM_I64_S, WI_I32_FROM_I64 },
-    /* U64 */ { WI_NOP,         WI_I32_FROM_I64,    WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_NOP,            WI_NOP,            WI_F32_FROM_I64_U, WI_F64_FROM_I64_U, WI_I32_FROM_I64 },
-    /* F32 */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_I32_FROM_F32_S,  WI_I32_FROM_F32_U, WI_I64_FROM_F32_S, WI_I64_FROM_F32_U, WI_NOP,            WI_F64_FROM_F32,   WI_UNREACHABLE },
-    /* F64 */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_I32_FROM_F64_S,  WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64,   WI_NOP,            WI_UNREACHABLE },
-    /* PTR */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_NOP },
+    /* I8  */ { WI_NOP,         WI_NOP,             WI_I32_EXTEND_8_S,  WI_NOP,            WI_I32_EXTEND_8_S,  WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* U8  */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* I16 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_I32_EXTEND_16_S, WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* U16 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* I32 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_S, WI_I64_FROM_I32_S, WI_F32_FROM_I32_S, WI_F64_FROM_I32_S, WI_NOP,          WI_NOP         },
+    /* U32 */ { WI_NOP,         WI_NOP,             WI_NOP,             WI_NOP,            WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_F32_FROM_I32_U, WI_F64_FROM_I32_U, WI_NOP,          WI_NOP         },
+    /* I64 */ { WI_NOP,         WI_I32_FROM_I64,    WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_NOP,            WI_NOP,            WI_F32_FROM_I64_S, WI_F64_FROM_I64_S, WI_I32_FROM_I64, WI_UNREACHABLE },
+    /* U64 */ { WI_NOP,         WI_I32_FROM_I64,    WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_I32_FROM_I64,    WI_I32_FROM_I64,   WI_NOP,            WI_NOP,            WI_F32_FROM_I64_U, WI_F64_FROM_I64_U, WI_I32_FROM_I64, WI_UNREACHABLE },
+    /* F32 */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_I32_FROM_F32_S,  WI_I32_FROM_F32_U, WI_I64_FROM_F32_S, WI_I64_FROM_F32_U, WI_NOP,            WI_F64_FROM_F32,   WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* F64 */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_I32_FROM_F64_S,  WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64,   WI_NOP,            WI_UNREACHABLE,  WI_UNREACHABLE },
+    /* PTR */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_NOP,             WI_NOP,            WI_I64_FROM_I32_U, WI_I64_FROM_I32_U, WI_UNREACHABLE,    WI_UNREACHABLE,    WI_NOP,          WI_UNREACHABLE },
+    /* TYP */ { WI_UNREACHABLE, WI_UNREACHABLE,     WI_UNREACHABLE,     WI_UNREACHABLE,    WI_NOP,             WI_NOP,            WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,    WI_UNREACHABLE,  WI_NOP         },
 };
 
 EMIT_FUNC(cast, AstUnaryOp* cast) {
@@ -2621,6 +2627,12 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
         if      (from->Basic.size == 4) fromidx = 8;
         else if (from->Basic.size == 8) fromidx = 9;
     }
+    else if (from->Basic.flags & Basic_Flag_Boolean) {
+        fromidx = 0;
+    }
+    else if (from->Basic.flags & Basic_Flag_Type_Index) {
+        fromidx = 11;
+    }
 
     if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) {
         toidx = 10;
@@ -2634,6 +2646,12 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
         if      (to->Basic.size == 4) toidx = 8;
         else if (to->Basic.size == 8) toidx = 9;
     }
+    else if (to->Basic.flags & Basic_Flag_Boolean) {
+        toidx = 0;
+    }
+    else if (to->Basic.flags & Basic_Flag_Type_Index) {
+        toidx = 11;
+    }
 
     if (fromidx != -1 && toidx != -1) {
         WasmInstructionType cast_op = cast_map[fromidx][toidx];