added distinct types on primitive types
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 25 Nov 2021 02:32:53 +0000 (20:32 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 25 Nov 2021 02:32:53 +0000 (20:32 -0600)
core/conv.onyx
core/type_info/helper.onyx
core/type_info/type_info.onyx
include/astnodes.h
include/types.h
src/astnodes.c
src/parser.c
src/symres.c
src/types.c
src/wasm_emit.c
src/wasm_type_table.c

index 76eaf087ac52be2c8bcb9f37286f39705b28e29a..40836974cecec190962cbc68fb41b3c37740d560 100644 (file)
@@ -628,6 +628,15 @@ str_format_va :: (buffer: [] u8, format: str, va: [] any) -> str {
                         }
                     }
                 }
+
+                if info.kind == .Distinct {
+                    d := cast(^Type_Info_Distinct) info;
+
+                    output->write(d.name);
+                    output->write("[");
+                    print_any(output, formatting, any.{ v.data, d.base_type });
+                    output->write("]");
+                }
             }
         }
     }
index 9ddaf5eac37dd6f8c1ef0e98d9cd82defbfd599c..213c24079ad7a5be0029f2e0facbdc88efcc1d6b 100644 (file)
@@ -117,6 +117,11 @@ write_type_name :: (writer: ^io.Writer, t: type_expr) {
 
             write_type_name(writer, f.return_type);
         }            
+
+        case .Distinct {
+            d := cast(^Type_Info_Distinct) info;
+            io.write_str(writer, d.name);
+        }
     }
 }
 
index 3df1cc63eaffd6926d5467567ccc435a49b76eb6..2a256c5f127b1a0a1f28e1948c289f8b04272690 100644 (file)
@@ -20,6 +20,7 @@ Type_Info :: struct {
         Dynamic_Array      :: 0x09;
         Variadic_Argument  :: 0x0a;
         Enum               :: 0x0b;
+        Distinct           :: 0x0c;
     }
 
     kind := Kind.Invalid;
@@ -166,6 +167,13 @@ Type_Info_Compound :: struct {
     components : [] type_expr;
 }
 
+Type_Info_Distinct :: struct {
+    use base : Type_Info;
+
+    base_type: type_expr;
+    name: str;
+}
+
 get_type_info :: (t: type_expr) -> ^Type_Info {
     // Grossness to get around the fact that type_exprs are not technically comparable, because in most
     // cases you should not compare them as the number assigned to them is arbitrary.
index 8cf6d8228fff9ed9a98e616849606f991d388e54..939ff01357dc185f18c5b23da1d8109860a2ae91 100644 (file)
@@ -71,6 +71,7 @@
     NODE(TypeRawAlias)         \
     NODE(CompoundType)         \
     NODE(TypeOf)               \
+    NODE(DistinctType)         \
                                \
     NODE(Binding)              \
     NODE(Alias)                \
@@ -158,6 +159,7 @@ typedef enum AstKind {
     Ast_Kind_Type_Raw_Alias,
     Ast_Kind_Type_Compound,
     Ast_Kind_Typeof,
+    Ast_Kind_Distinct_Type,
     Ast_Kind_Type_End,
 
     Ast_Kind_Struct_Member,
@@ -907,6 +909,12 @@ struct AstTypeOf {
     AstTyped* expr;
     Type* resolved_type;
 };
+struct AstDistinctType {
+    AstType_base;
+    char *name;
+    AstType *base_type;
+    Type *dtcache;
+};
 
 // Top level nodes
 struct AstBinding       { AstTyped_base; AstNode* node; };
index d1b9e51a0f26882c668fc6e72fc69d0f7d63ab81..638adab64f6d2114d6e1cd7eb944f5d9bd52619c 100644 (file)
@@ -127,6 +127,10 @@ struct TypeWithOffset {
         char* name;                                               \
         Type* backing;                                            \
         b32   is_flags;                                           \
+    })                                                            \
+    TYPE_KIND(Distinct, struct {                                  \
+        char* name;                                               \
+        Type* base_type;                                          \
     })
 
 
index eafc64ddd270bf80b14676e316f8be4f06e4a939..55d6b13fab22288760af3b99e39e8b4ea3323cbb 100644 (file)
@@ -46,6 +46,7 @@ static const char* ast_node_names[] = {
     "TYPE RAW ALIAS",
     "COMPOUND TYPE",
     "TYPE OF",
+    "DISTINCT TYPE",
     "TYPE_END (BAD)",
 
     "STRUCT MEMBER",
@@ -900,6 +901,26 @@ b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
         }
     }
 
+    if (to->kind == Type_Kind_Distinct) {
+        if (!types_are_compatible(to->Distinct.base_type, from)) {
+            // :BadErrorMessage
+            *err_msg = "Cannot convert to a distinct type using the wrong base type.";
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    if (from->kind == Type_Kind_Distinct) {
+        if (!types_are_compatible(from->Distinct.base_type, to)) {
+            // :BadErrorMessage
+            *err_msg = "Cannot convert from a distinct type to the wrong destination type.";
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
     if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) {
         *err_msg = "Cannot cast to or from a slice.";
         return 0;
index 9c8dde2dc50f9157db5202e3634106add49e19f9..f59a8485b0075a53b792b22bee989904406f8267 100644 (file)
@@ -2717,23 +2717,33 @@ static AstTyped* parse_top_level_expression(OnyxParser* parser) {
     if (parser->curr->type == Token_Type_Keyword_Enum)      return (AstTyped *) parse_enum_declaration(parser);
     if (parser->curr->type == Token_Type_Keyword_Macro)     return (AstTyped *) parse_macro(parser);
 
-    if (parse_possible_directive(parser, "type")) {
-        AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
-        alias->to = parse_type(parser);
-        return (AstTyped *) alias;
-    }
+    if (parser->curr->type == '#') {
+        if (parse_possible_directive(parser, "type")) {
+            AstTypeAlias* alias = make_node(AstTypeAlias, Ast_Kind_Type_Alias);
+            alias->to = parse_type(parser);
+            return (AstTyped *) alias;
+        }
 
-    if (parse_possible_directive(parser, "match")) {
-        // :LinearTokenDependent
-        OnyxToken* directive_token = parser->curr - 2;
-        AstOverloadedFunction* ofunc = parse_overloaded_function(parser, directive_token);
-        return (AstTyped *) ofunc;
-    }
+        if (parse_possible_directive(parser, "match")) {
+            // :LinearTokenDependent
+            OnyxToken* directive_token = parser->curr - 2;
+            AstOverloadedFunction* ofunc = parse_overloaded_function(parser, directive_token);
+            return (AstTyped *) ofunc;
+        }
 
-    if (parse_possible_directive(parser, "init")) {
-        // :LinearTokenDependent
-        AstDirectiveInit *init = parse_init_directive(parser, parser->curr - 2);
-        return (AstTyped *) init;
+        if (parse_possible_directive(parser, "init")) {
+            // :LinearTokenDependent
+            AstDirectiveInit *init = parse_init_directive(parser, parser->curr - 2);
+            return (AstTyped *) init;
+        }
+
+        if (parse_possible_directive(parser, "distinct")) {
+            // :LinearTokenDependent
+            AstDistinctType *distinct = make_node(AstDistinctType, Ast_Kind_Distinct_Type);
+            distinct->token = parser->curr - 2;
+            distinct->base_type = parse_type(parser);
+            return (AstTyped *) distinct;
+        }
     }
 
     return parse_expression(parser, 1);
@@ -2812,6 +2822,7 @@ static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol
         case Ast_Kind_Struct_Type:
         case Ast_Kind_Poly_Struct_Type:
         case Ast_Kind_Enum_Type:
+        case Ast_Kind_Distinct_Type:
             ((AstStructType *) node)->name = generate_name_within_scope(parser, symbol);
             goto default_case;
 
index 069b9cd1790e760015ccb853be1e7191f8ccf9bf..3d2094394584cd3f2a7c0dfd51416d215cdca6ef 100644 (file)
@@ -221,6 +221,12 @@ static SymresStatus symres_type(AstType** type) {
             SYMRES(expression, &type_of->expr);
             break;
         }
+
+        case Ast_Kind_Distinct_Type: {
+            AstDistinctType *distinct = (AstDistinctType *) *type;
+            SYMRES(type, &distinct->base_type);
+            break;
+        }
     }
 
     return Symres_Success;
index c89fd32084c59c42a6dce2d4910972399a8c66f6..9ffdfaf68892e4438eda4c1116b36714846c2e09 100644 (file)
@@ -188,6 +188,10 @@ b32 types_are_compatible_(Type* t1, Type* t2, b32 recurse_pointers) {
             return 1;
         }
 
+        case Type_Kind_Distinct:
+            // If the above cases didn't catch it, then these distinct types are not compatible.
+            return 0;
+
         default:
             assert(("Invalid type", 0));
             break;
@@ -214,6 +218,7 @@ u32 type_size_of(Type* type) {
         case Type_Kind_VarArgs:  return 16; // but there are alignment issues right now with that so I decided to not fight it and just make them 16 bytes in size.
         case Type_Kind_DynArray: return 32; // data (8), count (4), capacity (4), allocator { func (4), ---(4), data (8) }
         case Type_Kind_Compound: return type->Compound.size;
+        case Type_Kind_Distinct: return type_size_of(type->Distinct.base_type);
         default:                 return 0;
     }
 }
@@ -232,6 +237,7 @@ u32 type_alignment_of(Type* type) {
         case Type_Kind_VarArgs:  return 8;
         case Type_Kind_DynArray: return 8;
         case Type_Kind_Compound: return 4; // HACK
+        case Type_Kind_Distinct: return type_alignment_of(type->Distinct.base_type);
         default: return 1;
     }
 }
@@ -612,6 +618,26 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             
             return NULL;
         }
+
+        case Ast_Kind_Distinct_Type: {
+            AstDistinctType* distinct = (AstDistinctType *) type_node;
+            if (distinct->dtcache) return distinct->dtcache;
+
+            Type *base_type = type_build_from_ast(alloc, distinct->base_type);
+            if (base_type == NULL) return NULL;
+            if (base_type->kind != Type_Kind_Basic) {
+                onyx_report_error(distinct->token->pos, "Distinct types can only be made out of primitive types. '%s' is not a primitive type.", type_get_name(base_type));
+                return NULL;
+            }
+
+            Type *distinct_type = type_create(Type_Kind_Distinct, alloc, 0);
+            distinct_type->Distinct.base_type = base_type;
+            distinct_type->Distinct.name = distinct->name;
+            distinct->dtcache = distinct_type;
+
+            type_register(distinct_type);
+            return distinct_type;
+        }
     }
 
     return NULL;
@@ -876,6 +902,9 @@ const char* type_get_unique_name(Type* type) {
             return bh_aprintf(global_scratch_allocator, "%s", buf);
         }
 
+        case Type_Kind_Distinct: {
+            return bh_aprintf(global_scratch_allocator, "%s@%l", type->Distinct.name, type->id);
+        }
 
         default: return "unknown";
     }
@@ -935,6 +964,10 @@ const char* type_get_name(Type* type) {
             return bh_aprintf(global_scratch_allocator, "%s", buf);
         }
 
+        case Type_Kind_Distinct: {
+            return bh_aprintf(global_scratch_allocator, "%s", type->Distinct.name);
+        }
+
         default: return "unknown";
     }
 }
@@ -1090,6 +1123,12 @@ b32 type_linear_member_lookup(Type* type, i32 idx, TypeWithOffset* two) {
         }
         case Type_Kind_Compound: *two = type->Compound.linear_members[idx]; return 1;
         case Type_Kind_Struct:   *two = type->Struct.linear_members[idx];   return 1;
+
+        case Type_Kind_Distinct:
+            two->type = type->Distinct.base_type;
+            two->offset = 0;
+            return 1;
+
         default: {
             if (idx > 0) return 0;
             two->offset = 0;
index 3dbe6e02ff3ca9c6d55e5d22cb9f84dfe503527d..2e8af1b9f2a98fc9f2bebc7b272531c382e4cd95 100644 (file)
@@ -39,6 +39,10 @@ static WasmType onyx_type_to_wasm_type(Type* type) {
         return onyx_type_to_wasm_type(type->Enum.backing);
     }
 
+    if (type->kind == Type_Kind_Distinct) {
+        return onyx_type_to_wasm_type(type->Distinct.base_type);
+    }
+
     if (type->kind == Type_Kind_Pointer) {
         return WASM_TYPE_PTR;
     }
@@ -84,6 +88,7 @@ static b32 local_is_wasm_local(AstTyped* local) {
     if (local->kind == Ast_Kind_Local && local->flags & Ast_Flag_Address_Taken) return 0;
     if (local->type->kind == Type_Kind_Basic) return 1;
     if (local->type->kind == Type_Kind_Enum && local->type->Enum.backing->kind == Type_Kind_Basic) return 1;
+    if (local->type->kind == Type_Kind_Distinct && local->type->Distinct.base_type->kind == Type_Kind_Basic) return 1;
     if (local->type->kind == Type_Kind_Pointer) return 1;
     return 0;
 }
@@ -613,6 +618,7 @@ EMIT_FUNC(store_instruction, Type* type, u32 offset) {
     }
 
     if (type->kind == Type_Kind_Enum)     type = type->Enum.backing;
+    if (type->kind == Type_Kind_Distinct) type = type->Distinct.base_type;
     if (type->kind == Type_Kind_Function) type = &basic_types[Basic_Kind_U32];
 
     u32 alignment = type_get_alignment_log2(type);
@@ -662,6 +668,7 @@ EMIT_FUNC(load_instruction, Type* type, u32 offset) {
     }
 
     if (type->kind == Type_Kind_Enum)     type = type->Enum.backing;
+    if (type->kind == Type_Kind_Distinct) type = type->Distinct.base_type;
     if (type->kind == Type_Kind_Function) type = &basic_types[Basic_Kind_U32];
 
     i32 load_size   = type_size_of(type);
@@ -2906,6 +2913,12 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
         return;
     }
 
+    if (to->kind == Type_Kind_Distinct || from->kind == Type_Kind_Distinct) {
+        // Nothing needs to be done because they are identical
+        *pcode = code;
+        return;
+    }
+
     i32 fromidx = -1, toidx = -1;
     if (from->Basic.flags & Basic_Flag_Pointer || from->kind == Type_Kind_Array) {
         fromidx = 10;
index f67f4823a2ba52f9ab04e54fa1d5318273f5eb7c..2712843d0377a89a3313f25bfabd4df2cb9e6bb0 100644 (file)
@@ -466,6 +466,23 @@ u64 build_type_table(OnyxWasmModule* module) {
 
                 break;
             }
+        
+            case Type_Kind_Distinct: {
+                u32 name_base = table_buffer.length;
+                u32 name_length = strlen(type->Distinct.name);
+                bh_buffer_append(&table_buffer, type->Distinct.name, name_length);
+                bh_buffer_align(&table_buffer, 8);
+
+                table_info[type_idx] = table_buffer.length;
+                bh_buffer_write_u32(&table_buffer, type->kind);
+                bh_buffer_write_u32(&table_buffer, type_size_of(type));
+                bh_buffer_write_u32(&table_buffer, type_alignment_of(type));
+                bh_buffer_write_u32(&table_buffer, type->Distinct.base_type->id);
+                PATCH;
+                bh_buffer_write_u64(&table_buffer, name_base);
+                bh_buffer_write_u64(&table_buffer, name_length);
+                break;
+            }
         }
     }