Browse Source

Implement basic runtime type information

This allows for `runtime.println_any` to work!
gingerBill 2 years ago
parent
commit
b934e4b564
8 changed files with 459 additions and 71 deletions
  1. 1 1
      src/tilde.cpp
  2. BIN
      src/tilde/tb.lib
  3. 1 2
      src/tilde_builtin.cpp
  4. 51 30
      src/tilde_const.cpp
  5. 219 10
      src/tilde_expr.cpp
  6. 2 3
      src/tilde_proc.cpp
  7. 18 25
      src/tilde_stmt.cpp
  8. 167 0
      src/tilde_type_info.cpp

+ 1 - 1
src/tilde.cpp

@@ -260,7 +260,7 @@ gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_
 		}
 		}
 	}
 	}
 	if (err_on_not_found) {
 	if (err_on_not_found) {
-		GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index);
+		GB_PANIC("NOT FOUND lb_type_info_index '%s' @ index %td", type_to_string(type), index);
 	}
 	}
 	return -1;
 	return -1;
 }
 }

BIN
src/tilde/tb.lib


+ 1 - 2
src/tilde_builtin.cpp

@@ -267,8 +267,7 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr
 			pos = e->token.pos;
 			pos = e->token.pos;
 
 
 		}
 		}
-		GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global");
-		// return cg_emit_source_code_location_as_global(p, procedure, pos);
+		return cg_emit_source_code_location_as_global(p, procedure, pos);
 	} break;
 	} break;
 
 
 	case BuiltinProc_len: {
 	case BuiltinProc_len: {

+ 51 - 30
src/tilde_const.cpp

@@ -31,7 +31,7 @@ gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) {
 
 
 	if (is_type_internally_pointer_like(type)) {
 	if (is_type_internally_pointer_like(type)) {
 		return cg_value(tb_inst_uint(p->func, dt, 0), type);
 		return cg_value(tb_inst_uint(p->func, dt, 0), type);
-	} else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type)) {
+	} else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type) || is_type_typeid(type)) {
 		return cg_value(tb_inst_uint(p->func, dt, 0), type);
 		return cg_value(tb_inst_uint(p->func, dt, 0), type);
 	} else if (is_type_float(type)) {
 	} else if (is_type_float(type)) {
 		switch (size) {
 		switch (size) {
@@ -51,10 +51,49 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) {
 	return cg_const_nil(p->module, p, type);
 	return cg_const_nil(p->module, p, type);
 }
 }
 
 
+gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset);
+gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type);
+
+gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) {
+	// Source_Code_Location :: struct {
+	// 	file_path:    string,
+	// 	line, column: i32,
+	// 	procedure:    string,
+	// }
+
+	i64 file_path_offset = type_offset_of(t_source_code_location, 0);
+	i64 line_offset      = type_offset_of(t_source_code_location, 1);
+	i64 column_offset    = type_offset_of(t_source_code_location, 2);
+	i64 procedure_offset = type_offset_of(t_source_code_location, 3);
+
+	String file_path = get_file_path_string(pos.file_id);
+	if (file_path.len != 0) {
+		cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset);
+	}
+
+	void *line_ptr   = tb_global_add_region(m->mod, global, offset+line_offset,   4);
+	void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4);
+	cg_write_int_at_ptr(line_ptr,   pos.line,   t_i32);
+	cg_write_int_at_ptr(column_ptr, pos.column, t_i32);
+
+	if (proc_name.len != 0) {
+		cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset);
+	}
+}
+
 
 
 gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) {
 gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) {
-	// TODO(bill): cg_emit_source_code_location_as_global
-	return cg_const_nil(p, t_source_code_location);
+	cgModule *m = p->module;
+	char name[32] = {};
+	gb_snprintf(name, 31, "scl$%u", 1+m->const_nil_guid.fetch_add(1));
+
+	TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, t_source_code_location), TB_LINKAGE_PRIVATE);
+	tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_source_code_location), type_align_of(t_source_code_location), 6);
+
+	cg_global_source_code_location_const(m, proc_name, pos, global, 0);
+
+	TB_Node *ptr = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global);
+	return cg_lvalue_addr(ptr, t_source_code_location);
 }
 }
 
 
 
 
@@ -143,33 +182,6 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty
 	return global;
 	return global;
 }
 }
 
 
-gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) {
-	// Source_Code_Location :: struct {
-	// 	file_path:    string,
-	// 	line, column: i32,
-	// 	procedure:    string,
-	// }
-
-	i64 file_path_offset = type_offset_of(t_source_code_location, 0);
-	i64 line_offset      = type_offset_of(t_source_code_location, 1);
-	i64 column_offset    = type_offset_of(t_source_code_location, 2);
-	i64 procedure_offset = type_offset_of(t_source_code_location, 3);
-
-	String file_path = get_file_path_string(pos.file_id);
-	if (file_path.len != 0) {
-		cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset);
-	}
-
-	void *line_ptr   = tb_global_add_region(m->mod, global, offset+line_offset,   4);
-	void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4);
-	cg_write_int_at_ptr(line_ptr,   pos.line,   t_i32);
-	cg_write_int_at_ptr(column_ptr, pos.column, t_i32);
-
-	if (proc_name.len != 0) {
-		cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset);
-	}
-}
-
 gb_internal bool cg_elem_type_can_be_constant(Type *t) {
 gb_internal bool cg_elem_type_can_be_constant(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	if (t == t_invalid) {
 	if (t == t_invalid) {
@@ -1003,3 +1015,12 @@ gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) {
 gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) {
 gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) {
 	return cg_value(tb_inst_bool(p->func, v), type);
 	return cg_value(tb_inst_bool(p->func, v), type);
 }
 }
+
+gb_internal cgValue cg_const_string(cgProcedure *p, Type *type, String const &str) {
+	return cg_const_value(p, type, exact_value_string(str));
+}
+
+gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) {
+	return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v)));
+}
+

+ 219 - 10
src/tilde_expr.cpp

@@ -267,7 +267,8 @@ gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_t
 
 
 	GB_ASSERT(value.kind == cgValue_Value);
 	GB_ASSERT(value.kind == cgValue_Value);
 
 
-	value.node = tb_inst_bswap(p->func, value.node);
+	// TODO(bill): bswap
+	// value.node = tb_inst_bswap(p->func, value.node);
 	return cg_emit_transmute(p, value, end_type);
 	return cg_emit_transmute(p, value, end_type);
 }
 }
 
 
@@ -913,13 +914,12 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) {
 
 
 
 
 	if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) {
 	if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) {
-		GB_PANIC("TODO(bill): cstring_to_string call");
-		// TEMPORARY_ALLOCATOR_GUARD();
-		// lbValue c = lb_emit_conv(p, value, t_cstring);
-		// auto args = array_make<lbValue>(temporary_allocator(), 1);
-		// args[0] = c;
-		// lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args);
-		// return lb_emit_conv(p, s, dst);
+		TEMPORARY_ALLOCATOR_GUARD();
+		cgValue c = cg_emit_conv(p, value, t_cstring);
+		auto args = slice_make<cgValue>(temporary_allocator(), 1);
+		args[0] = c;
+		cgValue s = cg_emit_runtime_call(p, "cstring_to_string", args);
+		return cg_emit_conv(p, s, dst);
 	}
 	}
 
 
 	// float -> float
 	// float -> float
@@ -1115,7 +1115,29 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) {
 	}
 	}
 
 
 	if (is_type_any(dst)) {
 	if (is_type_any(dst)) {
-		GB_PANIC("TODO(bill): ? -> any");
+		if (is_type_untyped_nil(src) ||
+		    is_type_untyped_uninit(src)) {
+			return cg_const_nil(p, t);
+		}
+
+		cgAddr result = cg_add_local(p, t, nullptr, false);
+
+		Type *st = default_type(src_type);
+
+		cgValue data = cg_address_from_load_or_generate_local(p, value);
+		GB_ASSERT(is_type_pointer(data.type));
+		GB_ASSERT(is_type_typed(st));
+
+		data = cg_emit_conv(p, data, t_rawptr);
+
+		cgValue id = cg_typeid(p, st);
+		cgValue data_ptr = cg_emit_struct_ep(p, result.addr, 0);
+		cgValue id_ptr   = cg_emit_struct_ep(p, result.addr, 1);
+
+		cg_emit_store(p, data_ptr, data);
+		cg_emit_store(p, id_ptr,   id);
+
+		return cg_addr_load(p, result);
 	}
 	}
 
 
 	i64 src_sz = type_size_of(src);
 	i64 src_sz = type_size_of(src);
@@ -2868,6 +2890,190 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) {
 	return cg_build_addr_ptr(p, ue->expr);
 	return cg_build_addr_ptr(p, ue->expr);
 }
 }
 
 
+gb_internal cgValue cg_emit_cast_union(cgProcedure *p, cgValue value, Type *type, TokenPos pos) {
+	Type *src_type = value.type;
+	bool is_ptr = is_type_pointer(src_type);
+
+	bool is_tuple = true;
+	Type *tuple = type;
+	if (type->kind != Type_Tuple) {
+		is_tuple = false;
+		tuple = make_optional_ok_type(type);
+	}
+
+
+	if (is_ptr) {
+		value = cg_emit_load(p, value);
+	}
+	Type *src = base_type(type_deref(src_type));
+	GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type));
+	Type *dst = tuple->Tuple.variables[0]->type;
+
+	cgValue value_  = cg_address_from_load_or_generate_local(p, value);
+
+	if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) {
+		// just do a bit cast of the data at the front
+		cgValue ptr = cg_emit_conv(p, value_, alloc_type_pointer(type));
+		return cg_emit_load(p, ptr);
+	}
+
+
+	cgValue tag = {};
+	cgValue dst_tag = {};
+	cgValue cond = {};
+	cgValue data = {};
+
+	cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr;
+	cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr;
+
+	if (is_type_union_maybe_pointer(src)) {
+		data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type));
+	} else {
+		tag     = cg_emit_load(p, cg_emit_union_tag_ptr(p, value_));
+		dst_tag = cg_const_union_tag(p, src, dst);
+	}
+
+	TB_Node *ok_block  = cg_control_region(p, "union_cast_ok");
+	TB_Node *end_block = cg_control_region(p, "union_cast_end");
+
+	if (data.node != nullptr) {
+		GB_ASSERT(is_type_union_maybe_pointer(src));
+		cond = cg_emit_comp_against_nil(p, Token_NotEq, data);
+	} else {
+		cond = cg_emit_comp(p, Token_CmpEq, tag, dst_tag);
+	}
+
+	cg_emit_if(p, cond, ok_block, end_block);
+	tb_inst_set_control(p->func, ok_block);
+
+	if (data.node == nullptr) {
+		data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type));
+	}
+	cg_emit_store(p, gep0, data);
+	cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true));
+
+	cg_emit_goto(p, end_block);
+	tb_inst_set_control(p->func, end_block);
+
+	if (!is_tuple) {
+		GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0);
+		// NOTE(bill): Panic on invalid conversion
+		Type *dst_type = tuple->Tuple.variables[0]->type;
+
+		isize arg_count = 7;
+		if (build_context.no_rtti) {
+			arg_count = 4;
+		}
+
+		cgValue ok = cg_emit_load(p, gep1);
+		auto args = slice_make<cgValue>(permanent_allocator(), arg_count);
+		args[0] = ok;
+
+		args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id));
+		args[2] = cg_const_int(p, t_i32, pos.line);
+		args[3] = cg_const_int(p, t_i32, pos.column);
+
+		if (!build_context.no_rtti) {
+			args[4] = cg_typeid(p, src_type);
+			args[5] = cg_typeid(p, dst_type);
+			args[6] = cg_emit_conv(p, value_, t_rawptr);
+		}
+		cg_emit_runtime_call(p, "type_assertion_check2", args);
+
+		return cg_emit_load(p, gep0);
+	}
+
+	return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple);
+}
+
+gb_internal cgValue cg_emit_cast_any(cgProcedure *p, cgValue value, Type *type, TokenPos pos) {
+	Type *src_type = value.type;
+
+	if (is_type_pointer(src_type)) {
+		value = cg_emit_load(p, value);
+	}
+
+	bool is_tuple = true;
+	Type *tuple = type;
+	if (type->kind != Type_Tuple) {
+		is_tuple = false;
+		tuple = make_optional_ok_type(type);
+	}
+	Type *dst_type = tuple->Tuple.variables[0]->type;
+
+	if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) {
+		// just do a bit cast of the data at the front
+		cgValue ptr = cg_emit_struct_ev(p, value, 0);
+		ptr = cg_emit_conv(p, ptr, alloc_type_pointer(type));
+		return cg_emit_load(p, ptr);
+	}
+
+	cgValue dst_typeid = cg_typeid(p, dst_type);
+	cgValue any_typeid = cg_emit_struct_ev(p, value, 1);
+
+
+	TB_Node *ok_block = cg_control_region(p, "any_cast_ok");
+	TB_Node *end_block = cg_control_region(p, "any_cast_end");
+	cgValue cond = cg_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid);
+	cg_emit_if(p, cond, ok_block, end_block);
+	tb_inst_set_control(p->func, ok_block);
+
+	cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr;
+	cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr;
+
+	cgValue any_data = cg_emit_struct_ev(p, value, 0);
+	cgValue ptr = cg_emit_conv(p, any_data, alloc_type_pointer(dst_type));
+	cg_emit_store(p, gep0, cg_emit_load(p, ptr));
+	cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true));
+
+	cg_emit_goto(p, end_block);
+	tb_inst_set_control(p->func, end_block);
+
+	if (!is_tuple) {
+		// NOTE(bill): Panic on invalid conversion
+		cgValue ok = cg_emit_load(p, gep1);
+
+		isize arg_count = 7;
+		if (build_context.no_rtti) {
+			arg_count = 4;
+		}
+		auto args = slice_make<cgValue>(permanent_allocator(), arg_count);
+		args[0] = ok;
+
+		args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id));
+		args[2] = cg_const_int(p, t_i32, pos.line);
+		args[3] = cg_const_int(p, t_i32, pos.column);
+
+		if (!build_context.no_rtti) {
+			args[4] = any_typeid;
+			args[5] = dst_typeid;
+			args[6] = cg_emit_struct_ev(p, value, 0);
+		}
+		cg_emit_runtime_call(p, "type_assertion_check2", args);
+
+		return cg_emit_load(p, gep0);
+	}
+
+	return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple);
+}
+
+
+gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *type) {
+	ast_node(ta, TypeAssertion, expr);
+
+	TokenPos pos = ast_token(expr).pos;
+	cgValue e = cg_build_expr(p, ta->expr);
+	Type *t = type_deref(e.type);
+
+	if (is_type_union(t)) {
+		return cg_emit_cast_union(p, e, type, pos);
+	} else if (is_type_any(t)) {
+		return cg_emit_cast_any(p, e, type, pos);
+	}
+	GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type));
+	return {};
+}
+
 
 
 gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 	expr = unparen_expr(expr);
 	expr = unparen_expr(expr);
@@ -3079,8 +3285,11 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
 	case_ast_node(oe, OrElseExpr, expr);
 	case_ast_node(oe, OrElseExpr, expr);
 		return cg_build_or_else(p, oe->x, oe->y, tv.type);
 		return cg_build_or_else(p, oe->x, oe->y, tv.type);
 	case_end;
 	case_end;
+
+	case_ast_node(ta, TypeAssertion, expr);
+		return cg_build_type_assertion(p, expr, tv.type);
+	case_end;
 	}
 	}
-	GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind]));
 	return {};
 	return {};
 
 
 }
 }

+ 2 - 3
src/tilde_proc.cpp

@@ -352,7 +352,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
 	bool emit_asm = false;
 	bool emit_asm = false;
 
 
 	if (
 	if (
-	    // string_starts_with(p->name, str_lit("runtime@_os_write")) ||
+	    // string_starts_with(p->name, str_lit("bug@main")) ||
 	    false
 	    false
 	) {
 	) {
 		emit_asm = true;
 		emit_asm = true;
@@ -866,8 +866,7 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
 
 
 						cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0);
 						cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0);
 						cgValue len = cg_const_int(p, t_int, slice_len);
 						cgValue len = cg_const_int(p, t_int, slice_len);
-						GB_PANIC("TODO(bill): cg_fill_slice");
-						// cg_fill_slice(p, slice, base_elem, len);
+						cg_fill_slice(p, slice, base_elem, len);
 
 
 						variadic_args = cg_addr_load(p, slice);
 						variadic_args = cg_addr_load(p, slice);
 					}
 					}

+ 18 - 25
src/tilde_stmt.cpp

@@ -409,11 +409,9 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) {
 
 
 	switch (t->kind) {
 	switch (t->kind) {
 	case Type_Struct:
 	case Type_Struct:
-		{
-			type_set_offsets(t);
-			result_type = t->Struct.fields[index]->type;
-			offset = t->Struct.offsets[index];
-		}
+		type_set_offsets(t);
+		result_type = t->Struct.fields[index]->type;
+		offset = t->Struct.offsets[index];
 		break;
 		break;
 	case Type_Union:
 	case Type_Union:
 		GB_ASSERT(index == -1);
 		GB_ASSERT(index == -1);
@@ -421,7 +419,10 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) {
 		break;
 		break;
 		// return cg_emit_union_tag_ptr(p, s);
 		// return cg_emit_union_tag_ptr(p, s);
 	case Type_Tuple:
 	case Type_Tuple:
-		GB_PANIC("TODO(bill): cg_emit_tuple_ep");
+		type_set_offsets(t);
+		result_type = t->Tuple.variables[index]->type;
+		offset = t->Tuple.offsets[index];
+		GB_PANIC("TODO(bill): cg_emit_tuple_ep %d", s.kind);
 		break;
 		break;
 		// return cg_emit_tuple_ep(p, s, index);
 		// return cg_emit_tuple_ep(p, s, index);
 	case Type_Slice:
 	case Type_Slice:
@@ -1799,8 +1800,11 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) {
 				expr = unparen_expr(expr);
 				expr = unparen_expr(expr);
 				GB_ASSERT(!is_ast_range(expr));
 				GB_ASSERT(!is_ast_range(expr));
 				if (expr->tav.mode == Addressing_Type) {
 				if (expr->tav.mode == Addressing_Type) {
-					GB_PANIC("TODO(bill): cg_typeid as i64");
-					// key = cg_typeid(p, expr->tav.value.value_typeid);
+					Type *type = expr->tav.value.value_typeid;
+					if (type == nullptr || type == t_invalid) {
+						type = expr->tav.type;
+					}
+					key = cg_typeid_as_u64(p->module, type);
 				} else {
 				} else {
 					auto tv = type_and_value_of_expr(expr);
 					auto tv = type_and_value_of_expr(expr);
 					GB_ASSERT(tv.mode == Addressing_Constant);
 					GB_ASSERT(tv.mode == Addressing_Constant);
@@ -1912,21 +1916,16 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) {
 	cg_scope_close(p, cgDeferExit_Default, done);
 	cg_scope_close(p, cgDeferExit_Default, done);
 }
 }
 
 
-gb_internal void cg_type_case_body(cgProcedure *p, Ast *label, Ast *clause, TB_Node *body_region, TB_Node *done_region) {
-	// ast_node(cc, CaseClause, clause);
-
-	// cg_push_target_list(p, label, done, nullptr, nullptr);
-	// cg_build_stmt_list(p, cc->stmts);
-	// cg_scope_close(p, cgDeferExit_Default, body_region);
-	// cg_pop_target_list(p);
-
-	// cg_emit_goto(p, done_region);
-}
-
 gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) {
 gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) {
 	ast_node(ss, TypeSwitchStmt, node);
 	ast_node(ss, TypeSwitchStmt, node);
 
 
+	TB_Node *done_region = cg_control_region(p, "typeswitch_done");
+	TB_Node *else_region = done_region;
+	TB_Node *default_region = nullptr;
+	isize num_cases = 0;
+
 	cg_scope_open(p, ss->scope);
 	cg_scope_open(p, ss->scope);
+	defer (cg_scope_close(p, cgDeferExit_Default, done_region));
 
 
 	ast_node(as, AssignStmt, ss->tag);
 	ast_node(as, AssignStmt, ss->tag);
 	GB_ASSERT(as->lhs.count == 1);
 	GB_ASSERT(as->lhs.count == 1);
@@ -1969,11 +1968,6 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) {
 
 
 	ast_node(body, BlockStmt, ss->body);
 	ast_node(body, BlockStmt, ss->body);
 
 
-	TB_Node *done_region = cg_control_region(p, "typeswitch_done");
-	TB_Node *else_region = done_region;
-	TB_Node *default_region = nullptr;
-	isize num_cases = 0;
-
 	for (Ast *clause : body->stmts) {
 	for (Ast *clause : body->stmts) {
 		ast_node(cc, CaseClause, clause);
 		ast_node(cc, CaseClause, clause);
 		num_cases += cc->list.count;
 		num_cases += cc->list.count;
@@ -2158,7 +2152,6 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) {
 
 
 	cg_emit_goto(p, done_region);
 	cg_emit_goto(p, done_region);
 	tb_inst_set_control(p->func, done_region);
 	tb_inst_set_control(p->func, done_region);
-	cg_scope_close(p, cgDeferExit_Default, done_region);
 }
 }
 
 
 
 

+ 167 - 0
src/tilde_type_info.cpp

@@ -340,6 +340,173 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
 				break;
 				break;
 			}
 			}
 			break;
 			break;
+
+		case Type_Pointer:
+			tag_type = t_type_info_pointer;
+			cg_global_const_type_info_ptr(m, type_table_array, t->Pointer.elem, global, offset+0);
+			break;
+		case Type_MultiPointer:
+			tag_type = t_type_info_multi_pointer;
+			cg_global_const_type_info_ptr(m, type_table_array, t->MultiPointer.elem, global, offset+0);
+			break;
+		case Type_SoaPointer:
+			tag_type = t_type_info_soa_pointer;
+			cg_global_const_type_info_ptr(m, type_table_array, t->SoaPointer.elem, global, offset+0);
+			break;
+
+		case Type_Array:
+			{
+				tag_type = t_type_info_array;
+
+				cg_global_const_type_info_ptr(m, type_table_array, t->Array.elem, global, offset+0);
+				void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size);
+				void *count_ptr     = tb_global_add_region(m->mod, global, offset+2*build_context.int_size, build_context.int_size);
+
+				cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Array.elem), t_int);
+				cg_write_int_at_ptr(count_ptr,     t->Array.count,              t_int);
+			}
+			break;
+
+		case Type_EnumeratedArray:
+			{
+				tag_type = t_type_info_enumerated_array;
+
+				i64 elem_offset      = type_offset_of(tag_type, 0);
+				i64 index_offset     = type_offset_of(tag_type, 1);
+				i64 elem_size_offset = type_offset_of(tag_type, 2);
+				i64 count_offset     = type_offset_of(tag_type, 3);
+				i64 min_value_offset = type_offset_of(tag_type, 4);
+				i64 max_value_offset = type_offset_of(tag_type, 5);
+				i64 is_sparse_offset = type_offset_of(tag_type, 6);
+
+				cg_global_const_type_info_ptr(m, type_table_array, t->EnumeratedArray.elem,  global, offset+elem_offset);
+				cg_global_const_type_info_ptr(m, type_table_array, t->EnumeratedArray.index, global, offset+index_offset);
+
+				void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+elem_size_offset, build_context.int_size);
+				void *count_ptr     = tb_global_add_region(m->mod, global, offset+count_offset,     build_context.int_size);
+
+				void *min_value_ptr = tb_global_add_region(m->mod, global, offset+min_value_offset, type_size_of(t_type_info_enum_value));
+				void *max_value_ptr = tb_global_add_region(m->mod, global, offset+max_value_offset, type_size_of(t_type_info_enum_value));
+				void *is_sparse_ptr = tb_global_add_region(m->mod, global, offset+is_sparse_offset, 1);
+
+				cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->EnumeratedArray.elem), t_int);
+				cg_write_int_at_ptr(count_ptr,     t->EnumeratedArray.count,              t_int);
+
+				cg_write_int_at_ptr(min_value_ptr, exact_value_to_i64(*t->EnumeratedArray.min_value), t_type_info_enum_value);
+				cg_write_int_at_ptr(max_value_ptr, exact_value_to_i64(*t->EnumeratedArray.max_value), t_type_info_enum_value);
+				*(bool *)is_sparse_ptr = t->EnumeratedArray.is_sparse;
+			}
+			break;
+
+		case Type_DynamicArray:
+			{
+				tag_type = t_type_info_dynamic_array;
+
+				cg_global_const_type_info_ptr(m, type_table_array, t->DynamicArray.elem, global, offset+0);
+				void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size);
+				cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->DynamicArray.elem), t_int);
+			}
+			break;
+		case Type_Slice:
+			{
+				tag_type = t_type_info_slice;
+
+				cg_global_const_type_info_ptr(m, type_table_array, t->Slice.elem, global, offset+0);
+				void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size);
+				cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Slice.elem), t_int);
+			}
+			break;
+
+		case Type_Proc:
+			{
+				tag_type = t_type_info_procedure;
+
+				i64 params_offset     = type_offset_of(tag_type, 0);
+				i64 results_offset    = type_offset_of(tag_type, 1);
+				i64 variadic_offset   = type_offset_of(tag_type, 2);
+				i64 convention_offset = type_offset_of(tag_type, 3);
+
+				if (t->Proc.params) {
+					cg_global_const_type_info_ptr(m, type_table_array, t->Proc.params, global, offset+params_offset);
+				}
+				if (t->Proc.results) {
+					cg_global_const_type_info_ptr(m, type_table_array, t->Proc.results, global, offset+results_offset);
+				}
+
+				bool *variadic_ptr   = cast(bool *)tb_global_add_region(m->mod, global, offset+variadic_offset,   1);
+				u8 *  convention_ptr = cast(u8 *)  tb_global_add_region(m->mod, global, offset+convention_offset, 1);
+
+				*variadic_ptr = t->Proc.variadic;
+				*convention_ptr = cast(u8)t->Proc.calling_convention;
+			}
+			break;
+
+		case Type_Tuple:
+			{
+				tag_type = t_type_info_parameters;
+
+				// TODO(bill): Type_Info_Parameters
+			}
+			break;
+
+		case Type_Enum:
+			{
+				tag_type = t_type_info_enum;
+
+				// TODO(bill): Type_Info_Enum
+			}
+			break;
+		case Type_Struct:
+			{
+				tag_type = t_type_info_struct;
+
+				// TODO(bill): Type_Info_Struct
+			}
+			break;
+		case Type_Union:
+			{
+				tag_type = t_type_info_union;
+
+				// TODO(bill): Type_Info_Union
+			}
+			break;
+		case Type_Map:
+			{
+				tag_type = t_type_info_map;
+
+				// TODO(bill): Type_Info_Map
+			}
+			break;
+		case Type_BitSet:
+			{
+				tag_type = t_type_info_bit_set;
+
+				// TODO(bill): Type_Info_Bit_Set
+			}
+			break;
+		case Type_SimdVector:
+			{
+				tag_type = t_type_info_simd_vector;
+
+				// TODO(bill): Type_Info_Simd_Vector
+			}
+			break;
+
+		case Type_RelativePointer:
+			{
+				tag_type = t_type_info_relative_pointer;
+			}
+			break;
+		case Type_RelativeSlice:
+			{
+				tag_type = t_type_info_relative_slice;
+			}
+			break;
+		case Type_Matrix:
+			{
+				tag_type = t_type_info_matrix;
+			}
+			break;
 		}
 		}
 
 
 		if (tag_type != nullptr) {
 		if (tag_type != nullptr) {