Browse Source

Add `Type` -- Runtime type for comparing types (similar to TypeInfo but simpler)

Ginger Bill 8 years ago
parent
commit
001baf4419
10 changed files with 167 additions and 40 deletions
  1. 18 6
      code/demo.odin
  2. 1 0
      core/_preload.odin
  3. 22 2
      src/check_expr.cpp
  4. 5 1
      src/check_stmt.cpp
  5. 35 24
      src/checker.cpp
  6. 17 0
      src/exact_value.cpp
  7. 48 6
      src/ir.cpp
  8. 6 0
      src/ir_print.cpp
  9. 1 1
      src/parser.cpp
  10. 14 0
      src/types.cpp

+ 18 - 6
code/demo.odin

@@ -8,7 +8,6 @@ import (
 	"mem.odin";
 	"opengl.odin";
 	"os.odin";
-	"pool.odin";
 	"raw.odin";
 	"strconv.odin";
 	"strings.odin";
@@ -327,11 +326,11 @@ explicit_parametric_polymorphic_procedures :: proc() {
 
 
 
-	new_entity :: proc(manager: ^EntityManager, Type: type, x, y: int) -> ^Type {
-		result := new(Type);
+	new_entity :: proc(manager: ^EntityManager, T: type, x, y: int) -> ^T {
+		result := new(T);
 		result.entity = gen_new_entity(manager);
 		result.derived.data = result;
-		result.derived.type_info = type_info(Type);
+		result.derived.type_info = type_info(T);
 
 		result.position.x = f32(x);
 		result.position.y = f32(y);
@@ -345,14 +344,14 @@ explicit_parametric_polymorphic_procedures :: proc() {
 	rock    := new_entity(&manager, Rock, 3, 5);
 
 	// Named arguments work too!
-	door    := new_entity(manager = &manager, Type = Door, x = 3, y = 6);
+	door    := new_entity(manager = &manager, T = Door, x = 3, y = 6);
 
 	// And named arguments can be any order
 	monster := new_entity(
 		y = 1,
 		x = 2,
 		manager = &manager,
-		Type = Monster,
+		T = Monster,
 	);
 
 	append(entities, rock, door, monster);
@@ -380,6 +379,19 @@ main :: proc() {
 	// Command line argument(s)!
 	// -opt=0,1,2,3
 
+	a: Type = int;
+	b: Type = f32;
+	c: Type = int;
+	match a {
+	case int: fmt.println("a == int");
+	case f32: fmt.println("a == f32");
+	case:     fmt.println("What type is a?");
+	}
+	assert(a != b);
+	assert(b != c);
+	assert(a == c);
+
+
 	program := "+ + * - /";
 	accumulator := 0;
 

+ 1 - 0
core/_preload.odin

@@ -61,6 +61,7 @@ TypeInfo :: union {
 	String{},
 	Boolean{},
 	Any{},
+	Type{},
 	Pointer{
 		elem: ^TypeInfo, // nil -> rawptr
 	},

+ 22 - 2
src/check_expr.cpp

@@ -328,6 +328,14 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 		return;
 	}
 
+	if (operand->mode == Addressing_Type) {
+		if (type != NULL && is_type_type(type)) {
+			add_type_info_type(c, type);
+			add_type_info_type(c, operand->type);
+			return;
+		}
+	}
+
 	if (is_type_untyped(operand->type)) {
 		Type *target_type = type;
 		if (type == NULL || is_type_any(type)) {
@@ -2604,6 +2612,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 	o->mode = Addressing_Value;
 }
 
+
 void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
 	if (x->mode == Addressing_Type && y->mode == Addressing_Type) {
 		bool comp = are_types_identical(x->type, y->type);
@@ -2616,6 +2625,15 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
 		x->value = exact_value_bool(comp);
 		return;
 	}
+	if (x->mode == Addressing_Type && is_operand_a_type_value(*y)) {
+		x->mode = Addressing_Value;
+		x->type = t_untyped_bool;
+		return;
+	} else if (y->mode == Addressing_Type && is_operand_a_type_value(*x)) {
+		x->mode = Addressing_Value;
+		x->type = t_untyped_bool;
+		return;
+	}
 
 	gbString err_str = NULL;
 	gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
@@ -3046,11 +3064,13 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 		check_expr_or_type(c, y, be->right);
 		bool xt = x->mode == Addressing_Type;
 		bool yt = y->mode == Addressing_Type;
+		bool xvt = is_operand_a_type_value(*x);
+		bool yvt = is_operand_a_type_value(*y);
 		// If only one is a type, this is an error
 		if (xt ^ yt) {
 			GB_ASSERT(xt != yt);
-			if (xt) error_operand_not_expression(x);
-			if (yt) error_operand_not_expression(y);
+			if (xt && !yvt) error_operand_not_expression(x);
+			if (yt && !xvt) error_operand_not_expression(y);
 		}
 	} break;
 

+ 5 - 1
src/check_stmt.cpp

@@ -1297,7 +1297,11 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
 					check_comparison(c, &a1, &b1, op);
 				} else {
 					Operand y = {};
-					check_expr(c, &y, expr);
+					if (is_operand_a_type_value(x)) {
+						check_expr_or_type(c, &y, expr);
+					} else {
+						check_expr(c, &y, expr);
+					}
 					if (x.mode == Addressing_Invalid ||
 					    y.mode == Addressing_Invalid) {
 						continue;

+ 35 - 24
src/checker.cpp

@@ -170,6 +170,9 @@ bool is_operand_value(Operand o) {
 bool is_operand_nil(Operand o) {
 	return o.mode == Addressing_Value && o.type == t_untyped_nil;
 }
+bool is_operand_a_type_value(Operand o) {
+	return is_operand_value(o) && is_type_type(o.type);
+}
 
 
 struct BlockLabel {
@@ -325,7 +328,7 @@ DeclInfo *   decl_info_of_ident     (CheckerInfo *i, AstNode *ident);
 DeclInfo *   decl_info_of_entity    (CheckerInfo *i, Entity * e);
 AstFile *    ast_file_of_filename   (CheckerInfo *i, String   filename);
 // IMPORTANT: Only to use once checking is done
-isize        type_info_index        (CheckerInfo *i, Type *   type);
+isize        type_info_index        (CheckerInfo *i, Type *   type, bool error_on_failure = true);
 
 
 Entity *current_scope_lookup_entity(Scope *s, String name);
@@ -879,7 +882,7 @@ void check_remove_expr_info(CheckerInfo *i, AstNode *expr) {
 
 
 
-isize type_info_index(CheckerInfo *info, Type *type) {
+isize type_info_index(CheckerInfo *info, Type *type, bool error_on_failure) {
 	type = default_type(type);
 
 	isize entry_index = -1;
@@ -903,7 +906,7 @@ isize type_info_index(CheckerInfo *info, Type *type) {
 		}
 	}
 
-	if (entry_index < 0) {
+	if (error_on_failure && entry_index < 0) {
 		compiler_error("TypeInfo for `%s` could not be found", type_to_string(type));
 	}
 	return entry_index;
@@ -1086,6 +1089,9 @@ void add_type_info_type(Checker *c, Type *t) {
 			add_type_info_type(c, t_type_info_ptr);
 			add_type_info_type(c, t_rawptr);
 			break;
+		case Basic_Type:
+			add_type_info_type(c, t_type_info_type);
+			break;
 
 		case Basic_complex64:
 			add_type_info_type(c, t_type_info_float);
@@ -1248,9 +1254,12 @@ Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start)
 
 	for_array(i, info->definitions.entries) {
 		Entity *e = info->definitions.entries[i].value;
-		if (e->scope->is_global && !is_type_polymorphic(e->type)) { // TODO(bill): is the check enough?
-			// NOTE(bill): Require runtime stuff
-			add_dependency_to_map(&map, info, e);
+		// if (e->scope->is_global && !is_type_poly_proc(e->type)) { // TODO(bill): is the check enough?
+		if (e->scope->is_global) { // TODO(bill): is the check enough?
+			if (!is_type_poly_proc(e->type))  {
+				// NOTE(bill): Require runtime stuff
+				add_dependency_to_map(&map, info, e);
+			}
 		} else if (e->kind == Entity_Procedure) {
 			if ((e->Procedure.tags & ProcTag_export) != 0) {
 				add_dependency_to_map(&map, info, e);
@@ -1299,7 +1308,7 @@ void init_preload(Checker *c) {
 
 
 
-		if (record->variant_count != 23) {
+		if (record->variant_count != 24) {
 			compiler_error("Invalid `TypeInfo` layout");
 		}
 		t_type_info_named         = record->variants[ 1]->type;
@@ -1310,20 +1319,21 @@ void init_preload(Checker *c) {
 		t_type_info_string        = record->variants[ 6]->type;
 		t_type_info_boolean       = record->variants[ 7]->type;
 		t_type_info_any           = record->variants[ 8]->type;
-		t_type_info_pointer       = record->variants[ 9]->type;
-		t_type_info_atomic        = record->variants[10]->type;
-		t_type_info_procedure     = record->variants[11]->type;
-		t_type_info_array         = record->variants[12]->type;
-		t_type_info_dynamic_array = record->variants[13]->type;
-		t_type_info_slice         = record->variants[14]->type;
-		t_type_info_vector        = record->variants[15]->type;
-		t_type_info_tuple         = record->variants[16]->type;
-		t_type_info_struct        = record->variants[17]->type;
-		t_type_info_raw_union     = record->variants[18]->type;
-		t_type_info_union         = record->variants[19]->type;
-		t_type_info_enum          = record->variants[20]->type;
-		t_type_info_map           = record->variants[21]->type;
-		t_type_info_bit_field     = record->variants[22]->type;
+		t_type_info_type          = record->variants[ 9]->type;
+		t_type_info_pointer       = record->variants[10]->type;
+		t_type_info_atomic        = record->variants[11]->type;
+		t_type_info_procedure     = record->variants[12]->type;
+		t_type_info_array         = record->variants[13]->type;
+		t_type_info_dynamic_array = record->variants[14]->type;
+		t_type_info_slice         = record->variants[15]->type;
+		t_type_info_vector        = record->variants[16]->type;
+		t_type_info_tuple         = record->variants[17]->type;
+		t_type_info_struct        = record->variants[18]->type;
+		t_type_info_raw_union     = record->variants[19]->type;
+		t_type_info_union         = record->variants[20]->type;
+		t_type_info_enum          = record->variants[21]->type;
+		t_type_info_map           = record->variants[22]->type;
+		t_type_info_bit_field     = record->variants[23]->type;
 
 		t_type_info_named_ptr         = make_type_pointer(c->allocator, t_type_info_named);
 		t_type_info_integer_ptr       = make_type_pointer(c->allocator, t_type_info_integer);
@@ -1333,6 +1343,7 @@ void init_preload(Checker *c) {
 		t_type_info_string_ptr        = make_type_pointer(c->allocator, t_type_info_string);
 		t_type_info_boolean_ptr       = make_type_pointer(c->allocator, t_type_info_boolean);
 		t_type_info_any_ptr           = make_type_pointer(c->allocator, t_type_info_any);
+		t_type_info_type_ptr          = make_type_pointer(c->allocator, t_type_info_type);
 		t_type_info_pointer_ptr       = make_type_pointer(c->allocator, t_type_info_pointer);
 		t_type_info_atomic_ptr        = make_type_pointer(c->allocator, t_type_info_atomic);
 		t_type_info_procedure_ptr     = make_type_pointer(c->allocator, t_type_info_procedure);
@@ -2197,6 +2208,9 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) {
 void check_parsed_files(Checker *c) {
 	Map<Scope *> file_scopes; // Key: String (fullpath)
 	map_init(&file_scopes, heap_allocator());
+	defer (map_destroy(&file_scopes));
+
+	add_type_info_type(c, t_invalid);
 
 	// Map full filepaths to Scopes
 	for_array(i, c->parser->files) {
@@ -2349,7 +2363,4 @@ void check_parsed_files(Checker *c) {
 			}
 		}
 	}
-
-	map_destroy(&file_scopes);
-
 }

+ 17 - 0
src/exact_value.cpp

@@ -5,6 +5,8 @@
 
 struct AstNode;
 struct HashKey;
+struct Type;
+bool are_types_identical(Type *x, Type *y);
 
 struct Complex128 {
 	f64 real, imag;
@@ -20,6 +22,7 @@ enum ExactValueKind {
 	ExactValue_Complex,
 	ExactValue_Pointer,
 	ExactValue_Compound, // TODO(bill): Is this good enough?
+	ExactValue_Type,
 
 	ExactValue_Count,
 };
@@ -34,6 +37,7 @@ struct ExactValue {
 		i64           value_pointer;
 		Complex128    value_complex;
 		AstNode *     value_compound;
+		Type *        value_type;
 	};
 };
 
@@ -99,6 +103,12 @@ ExactValue exact_value_pointer(i64 ptr) {
 	return result;
 }
 
+ExactValue exact_value_type(Type *type) {
+	ExactValue result = {ExactValue_Type};
+	result.value_type = type;
+	return result;
+}
+
 
 ExactValue exact_value_integer_from_string(String string) {
 	return exact_value_u128(u128_from_string(string));
@@ -639,6 +649,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
 		case Token_GtEq:  return a >= b;
 		}
 	} break;
+
+	case ExactValue_Type:
+		switch (op) {
+		case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
+		case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
+		}
+		break;
 	}
 
 	GB_PANIC("Invalid comparison");

+ 48 - 6
src/ir.cpp

@@ -749,6 +749,7 @@ void     ir_build_defer_stmt    (irProcedure *proc, irDefer d);
 irAddr   ir_build_addr          (irProcedure *proc, AstNode *expr);
 void     ir_build_proc          (irValue *value, irProcedure *parent);
 void     ir_gen_global_type_name(irModule *m, Entity *e, String name);
+irValue *ir_get_type_info_ptr   (irProcedure *proc, Type *type);
 
 
 
@@ -2771,6 +2772,23 @@ String ir_lookup_subtype_polymorphic_field(CheckerInfo *info, Type *dst, Type *s
 }
 
 
+irValue *ir_emit_ptr_to_int(irProcedure *proc, irValue *value, Type *t, bool allow_type_type = false) {
+	Type *vt = core_type(ir_type(value));
+	GB_ASSERT(is_type_pointer(vt));
+	if (allow_type_type) {
+		GB_ASSERT(is_type_int_or_uint(core_type(t)) || is_type_type(t));
+	} else {
+		GB_ASSERT(is_type_int_or_uint(core_type(t)));
+	}
+	return ir_emit(proc, ir_instr_conv(proc, irConv_ptrtoint, value, vt, t));
+}
+irValue *ir_emit_int_to_ptr(irProcedure *proc, irValue *value, Type *t) {
+	Type *vt = core_type(ir_type(value));
+	GB_ASSERT(is_type_int_or_uint(vt));
+	GB_ASSERT(is_type_pointer(core_type(t)));
+	return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, value, vt, t));
+}
+
 
 irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 	Type *src_type = ir_type(value);
@@ -2925,10 +2943,10 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
 
 	// Pointer <-> int
 	if (is_type_pointer(src) && is_type_int_or_uint(dst)) {
-		return ir_emit(proc, ir_instr_conv(proc, irConv_ptrtoint, value, src_type, t));
+		return ir_emit_ptr_to_int(proc, value, t);
 	}
 	if (is_type_int_or_uint(src) && is_type_pointer(dst)) {
-		return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, value, src_type, t));
+		return ir_emit_int_to_ptr(proc, value, t);
 	}
 
 	if (is_type_union(dst)) {
@@ -4388,7 +4406,14 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 
 	if (tv.mode == Addressing_Type) {
 		// TODO(bill): Handle this correctly
-		return ir_value_nil(proc->module->allocator, tv.type);
+		i32 entry_index = type_info_index(proc->module->info, tv.type, false);
+		if (entry_index >= 0) {
+			irValue *ptr = ir_get_type_info_ptr(proc, tv.type);
+			return ir_emit_ptr_to_int(proc, ptr, t_type, true);
+			// i32 id = entry_index+1;
+			// return ir_value_constant(proc->module->allocator, t_int, exact_value_i64(id));
+		}
+		return v_raw_nil;
 	}
 
 	if (tv.value.kind != ExactValue_Invalid) {
@@ -4766,7 +4791,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			GB_ASSERT(!vari_expand);
 			isize i = 0;
 			for (; i < type->param_count-1; i++) {
-				args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
+				Entity *e = pt->variables[i];
+				if (e->kind == Entity_Variable) {
+					args[i] = ir_emit_conv(proc, args[i], e->type);
+				}
 			}
 			Type *variadic_type = pt->variables[i]->type;
 			GB_ASSERT(is_type_slice(variadic_type));
@@ -4783,7 +4811,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 		} else if (variadic) {
 			isize i = 0;
 			for (; i < type->param_count-1; i++) {
-				args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
+				Entity *e = pt->variables[i];
+				if (e->kind == Entity_Variable) {
+					args[i] = ir_emit_conv(proc, args[i], e->type);
+				}
 			}
 			if (!vari_expand) {
 				Type *variadic_type = pt->variables[i]->type;
@@ -4795,7 +4826,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 			}
 		} else {
 			for (isize i = 0; i < type->param_count; i++) {
-				args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
+				Entity *e = pt->variables[i];
+				if (e->kind == Entity_Variable) {
+					args[i] = ir_emit_conv(proc, args[i], e->type);
+				}
 			}
 		}
 
@@ -7698,6 +7732,10 @@ void ir_gen_tree(irGen *s) {
 				auto *entry = &info->type_info_map.entries[type_info_map_index];
 				Type *t = cast(Type *)entry->key.ptr;
 				t = default_type(t);
+				if (t == t_invalid) {
+					continue;
+				}
+
 				isize entry_index = type_info_index(info, t);
 
 				irValue *tag = NULL;
@@ -7771,6 +7809,10 @@ void ir_gen_tree(irGen *s) {
 					case Basic_any:
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_any_ptr);
 						break;
+
+					case Basic_Type:
+						tag = ir_emit_conv(proc, ti_ptr, t_type_info_type_ptr);
+						break;
 					}
 					break;
 

+ 6 - 0
src/ir_print.cpp

@@ -246,6 +246,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		case Basic_uint:   ir_fprintf(f, "i%lld", word_bits);         return;
 		case Basic_int:    ir_fprintf(f, "i%lld", word_bits);         return;
 		case Basic_any:    ir_fprintf(f, "%%..any");                  return;
+		case Basic_Type:   ir_fprintf(f, "%%..Type");                 return;
 		}
 		break;
 	case Type_Pointer:
@@ -1691,6 +1692,11 @@ void print_llvm_ir(irGen *ir) {
 	ir_print_type(f, m, t_type_info_ptr);
 	ir_fprintf(f, "} ; Basic_any\n");
 
+	ir_print_encoded_local(f, str_lit("..Type"));
+	ir_fprintf(f, " = type ");
+	ir_print_type(f, m, t_int);
+	ir_fprintf(f, " ; Basic_Type\n");
+
 	ir_fprintf(f, "declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone \n");
 	ir_fprintf(f, "\n");
 

+ 1 - 1
src/parser.cpp

@@ -138,7 +138,7 @@ Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
 // all the nodes and even memcpy in a different kind of node
 #define AST_NODE_KINDS \
 	AST_NODE_KIND(Ident,          "identifier",      struct { \
-		Token token; \
+		Token token;      \
 	}) \
 	AST_NODE_KIND(Implicit,       "implicit",        Token) \
 	AST_NODE_KIND(Undef,          "undef",           Token) \

+ 14 - 0
src/types.cpp

@@ -30,6 +30,7 @@ enum BasicKind {
 	Basic_rawptr,
 	Basic_string, // ^u8 + int
 	Basic_any,    // ^Type_Info + rawptr
+	Basic_Type,   // `int` id of the type
 
 	Basic_UntypedBool,
 	Basic_UntypedInteger,
@@ -261,6 +262,7 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_rawptr,            BasicFlag_Pointer,                         -1, STR_LIT("rawptr")}},
 	{Type_Basic, {Basic_string,            BasicFlag_String,                          -1, STR_LIT("string")}},
 	{Type_Basic, {Basic_any,               0,                                         -1, STR_LIT("any")}},
+	{Type_Basic, {Basic_Type,              0,                                         -1, STR_LIT("Type")}},
 
 	{Type_Basic, {Basic_UntypedBool,       BasicFlag_Boolean    | BasicFlag_Untyped,   0, STR_LIT("untyped bool")}},
 	{Type_Basic, {Basic_UntypedInteger,    BasicFlag_Integer    | BasicFlag_Untyped,   0, STR_LIT("untyped integer")}},
@@ -306,6 +308,7 @@ gb_global Type *t_uint            = &basic_types[Basic_uint];
 gb_global Type *t_rawptr          = &basic_types[Basic_rawptr];
 gb_global Type *t_string          = &basic_types[Basic_string];
 gb_global Type *t_any             = &basic_types[Basic_any];
+gb_global Type *t_type            = &basic_types[Basic_Type];
 
 gb_global Type *t_untyped_bool       = &basic_types[Basic_UntypedBool];
 gb_global Type *t_untyped_integer    = &basic_types[Basic_UntypedInteger];
@@ -340,6 +343,7 @@ gb_global Type *t_type_info_rune              = NULL;
 gb_global Type *t_type_info_float             = NULL;
 gb_global Type *t_type_info_complex           = NULL;
 gb_global Type *t_type_info_any               = NULL;
+gb_global Type *t_type_info_type              = NULL;
 gb_global Type *t_type_info_string            = NULL;
 gb_global Type *t_type_info_boolean           = NULL;
 gb_global Type *t_type_info_pointer           = NULL;
@@ -364,6 +368,7 @@ gb_global Type *t_type_info_float_ptr         = NULL;
 gb_global Type *t_type_info_complex_ptr       = NULL;
 gb_global Type *t_type_info_quaternion_ptr    = NULL;
 gb_global Type *t_type_info_any_ptr           = NULL;
+gb_global Type *t_type_info_type_ptr          = NULL;
 gb_global Type *t_type_info_string_ptr        = NULL;
 gb_global Type *t_type_info_boolean_ptr       = NULL;
 gb_global Type *t_type_info_pointer_ptr       = NULL;
@@ -775,6 +780,12 @@ bool is_type_tuple(Type *t) {
 	return t->kind == Type_Tuple;
 }
 
+bool is_type_type(Type *t) {
+	t = base_type(t);
+	return t->kind == Type_Basic && t->Basic.kind == Basic_Type;
+}
+
+
 
 bool is_type_int_or_uint(Type *t) {
 	if (t->kind == Type_Basic) {
@@ -1054,6 +1065,7 @@ bool is_type_comparable(Type *t) {
 		case Basic_any:
 			return false;
 		case Basic_rune:
+		case Basic_Type:
 			return true;
 		}
 		return true;
@@ -1747,6 +1759,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 		switch (t->Basic.kind) {
 		case Basic_string: return build_context.word_size;
 		case Basic_any:    return build_context.word_size;
+		case Basic_Type:   return build_context.word_size;
 
 		case Basic_int: case Basic_uint: case Basic_rawptr:
 			return build_context.word_size;
@@ -1972,6 +1985,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
 		switch (kind) {
 		case Basic_string: return 2*build_context.word_size;
 		case Basic_any:    return 2*build_context.word_size;
+		case Basic_Type:   return 1*build_context.word_size;
 
 		case Basic_int: case Basic_uint: case Basic_rawptr:
 			return build_context.word_size;