Browse Source

`type_info_of` allows `typeid`; `typeid_of` allows `^Type_Info`; Otherwise only allow type

gingerBill 7 years ago
parent
commit
373a60b9ef
5 changed files with 77 additions and 46 deletions
  1. 18 21
      core/_preload.odin
  2. 20 20
      core/fmt.odin
  3. 1 1
      core/mem.odin
  4. 17 0
      src/check_expr.cpp
  5. 21 4
      src/ir.cpp

+ 18 - 21
core/_preload.odin

@@ -211,7 +211,7 @@ __Map_Header :: struct {
 
 
 
-type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
+type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
 	if info == nil do return nil;
 
 	base := info;
@@ -225,7 +225,7 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 }
 
 
-type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
+type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
 	if info == nil do return nil;
 
 	base := info;
@@ -239,27 +239,24 @@ type_info_base_without_enum :: proc(info: ^Type_Info) -> ^Type_Info {
 	return base;
 }
 
-
-typeid_from_type_info :: proc(ti: ^Type_Info) -> typeid {
-	id: uintptr = 0;
-	if ti != nil {
-		id = (uintptr(ti) - uintptr(&__type_table[0]))/size_of(Type_Info);
-	}
+__typeid_of :: proc "contextless" (ti: ^Type_Info) -> typeid {
+	if ti == nil do return nil;
+	start := uintptr(&__type_table[0]);
+	end := uintptr(ti);
+	id := (end-start)/size_of(Type_Info);
 	return transmute(typeid)id;
 }
-type_info_from_typeid :: proc(t: typeid) -> ^Type_Info {
-	index := transmute(uintptr)t;
-	return &__type_table[index];
-}
-typeid_base :: proc(id: typeid) -> typeid {
-	ti := type_info_from_typeid(id);
+
+
+typeid_base :: proc "contextless" (id: typeid) -> typeid {
+	ti := type_info_of(id);
 	ti = type_info_base(ti);
-	return typeid_from_type_info(ti);
+	return typeid_of(ti);
 }
-typeid_base_without_enum :: proc(id: typeid) -> typeid {
-	ti := type_info_from_typeid(id);
+typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
+	ti := type_info_of(id);
 	ti = type_info_base_without_enum(ti);
-	return typeid_from_type_info(ti);
+	return typeid_of(ti);
 }
 
 
@@ -668,7 +665,7 @@ __print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location)
 	os.write_byte(fd, ')');
 }
 __print_typeid :: proc(fd: os.Handle, id: typeid) {
-	ti := type_info_from_typeid(id);
+	ti := type_info_of(id);
 	__print_type(fd, ti);
 }
 __print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
@@ -681,7 +678,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
 	case Type_Info_Named:
 		os.write_string(fd, info.name);
 	case Type_Info_Integer:
-		a := any{typeid = typeid_from_type_info(ti)};
+		a := any{typeid = typeid_of(ti)};
 		switch _ in a {
 		case int:     os.write_string(fd, "int");
 		case uint:    os.write_string(fd, "uint");
@@ -701,7 +698,7 @@ __print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
 	case Type_Info_String:
 		os.write_string(fd, "string");
 	case Type_Info_Boolean:
-		a := any{typeid = typeid_from_type_info(ti)};
+		a := any{typeid = typeid_of(ti)};
 		switch _ in a {
 		case bool: os.write_string(fd, "bool");
 		case:

+ 20 - 20
core/fmt.odin

@@ -151,7 +151,7 @@ fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
 }
 
 write_typeid :: proc(buf: ^String_Buffer, id: typeid) {
-	write_type(buf, type_info_from_typeid(id));
+	write_type(buf, type_info_of(id));
 }
 
 write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
@@ -164,7 +164,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
 	case Type_Info_Named:
 		write_string(buf, info.name);
 	case Type_Info_Integer:
-		a := any{typeid = typeid_from_type_info(ti)};
+		a := any{typeid = typeid_of(ti)};
 		switch _ in a {
 		case int:     write_string(buf, "int");
 		case uint:    write_string(buf, "uint");
@@ -188,7 +188,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
 			write_string(buf, "string");
 		}
 	case Type_Info_Boolean:
-		a := any{typeid = typeid_from_type_info(ti)};
+		a := any{typeid = typeid_of(ti)};
 		switch _ in a {
 		case bool: write_string(buf, "bool");
 		case:
@@ -629,7 +629,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
 
 enum_value_to_string :: proc(v: any) -> (string, bool) {
 	v.typeid = typeid_base(v.typeid);
-	type_info := type_info_from_typeid(v.typeid);
+	type_info := type_info_of(v.typeid);
 
 	switch e in type_info.variant {
 	case: return "", false;
@@ -653,7 +653,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
 			return "", false;
 		}
 
-		a := any{v.data, typeid_from_type_info(type_info_base(e.base))};
+		a := any{v.data, typeid_of(type_info_base(e.base))};
 		switch v in a {
 		case rune:    return get_str(v, e);
 		case i8:      return get_str(v, e);
@@ -696,14 +696,14 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		return;
 	}
 
-	type_info := type_info_from_typeid(v.typeid);
+	type_info := type_info_of(v.typeid);
 	switch e in type_info.variant {
 	case: fmt_bad_verb(fi, verb);
 	case Type_Info_Enum:
 		switch verb {
 		case: fmt_bad_verb(fi, verb);
 		case 'd', 'f':
-			fmt_arg(fi, any{v.data, typeid_from_type_info(type_info_base(e.base))}, verb);
+			fmt_arg(fi, any{v.data, typeid_of(type_info_base(e.base))}, verb);
 		case 's', 'v':
 			str, ok := enum_value_to_string(v);
 			if !ok do str = "!%(BAD ENUM VALUE)";
@@ -719,7 +719,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		return;
 	}
 
-	type_info := type_info_from_typeid(v.typeid);
+	type_info := type_info_of(v.typeid);
 	switch info in type_info.variant {
 	case Type_Info_Named:
 		switch b in info.base.variant {
@@ -755,7 +755,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 					write_string(fi.buf, "any{}");
 				} else {
 					data := rawptr(uintptr(v.data) + b.offsets[i]);
-					id := typeid_from_type_info(t);
+					id := typeid_of(t);
 					fmt_arg(fi, any{data, id}, 'v');
 				}
 
@@ -766,7 +766,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			write_byte(fi.buf, '}');
 
 		case:
-			fmt_value(fi, any{v.data, typeid_from_type_info(info.base)}, verb);
+			fmt_value(fi, any{v.data, typeid_of(info.base)}, verb);
 		}
 
 	case Type_Info_Boolean:    fmt_arg(fi, v, verb);
@@ -790,7 +790,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			if i > 0 do write_string(fi.buf, ", ");
 
 			data := uintptr(v.data) + uintptr(i*info.elem_size);
-			fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb);
+			fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
 		}
 
 	case Type_Info_Dynamic_Array:
@@ -801,7 +801,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			if i > 0 do write_string(fi.buf, ", ");
 
 			data := uintptr(array.data) + uintptr(i*info.elem_size);
-			fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb);
+			fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
 		}
 
 	case Type_Info_Slice:
@@ -812,7 +812,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			if i > 0 do write_string(fi.buf, ", ");
 
 			data := uintptr(slice.data) + uintptr(i*info.elem_size);
-			fmt_arg(fi, any{rawptr(data), typeid_from_type_info(info.elem)}, verb);
+			fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
 		}
 
 	case Type_Info_Map:
@@ -843,13 +843,13 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 					write_string(fi.buf, header.key.str);
 				} else {
 					fi := Fmt_Info{buf = fi.buf};
-					fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_from_type_info(info.key)}, 'v');
+					fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_of(info.key)}, 'v');
 				}
 
 				write_string(fi.buf, "=");
 
 				value := data + entry_type.offsets[2];
-				fmt_arg(fi, any{rawptr(value), typeid_from_type_info(info.value)}, 'v');
+				fmt_arg(fi, any{rawptr(value), typeid_of(info.value)}, 'v');
 			}
 		}
 
@@ -884,7 +884,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 				write_string(fi.buf, "any{}");
 			} else {
 				data := uintptr(v.data) + info.offsets[i];
-				id := typeid_from_type_info(t);
+				id := typeid_of(t);
 				fmt_arg(fi, any{rawptr(data), id}, 'v');
 			}
 			if hash do write_string(fi.buf, ",\n");
@@ -892,7 +892,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 
 	case Type_Info_Union:
 		tag_ptr := uintptr(v.data) + info.tag_offset;
-		tag_any := any{rawptr(tag_ptr), typeid_from_type_info(info.tag_type)};
+		tag_any := any{rawptr(tag_ptr), typeid_of(info.tag_type)};
 
 		tag: i64 = -1;
 		switch i in tag_any {
@@ -910,7 +910,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 		if v.data == nil || tag == 0 {
 			write_string(fi.buf, "nil");
 		} else {
-			id := typeid_from_type_info(info.variants[tag-1]);
+			id := typeid_of(info.variants[tag-1]);
 			fmt_arg(fi, any{v.data, id}, verb);
 		}
 
@@ -958,7 +958,7 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
 	fi.arg = arg;
 
 	if verb == 'T' {
-		ti := type_info_from_typeid(arg.typeid);
+		ti := type_info_of(arg.typeid);
 		switch a in arg {
 		case ^Type_Info: ti = a;
 		}
@@ -1015,7 +1015,7 @@ sbprint :: proc(buf: ^String_Buffer, args: ...any) -> string {
 	fi.buf = buf;
 
 	for arg, i in args {
-		is_string := arg != nil && types.is_string(type_info_from_typeid(arg.typeid));
+		is_string := arg != nil && types.is_string(type_info_of(arg.typeid));
 		if i > 0 && !is_string && !prev_string {
 			write_byte(buf, ' ');
 		}

+ 1 - 1
core/mem.odin

@@ -43,7 +43,7 @@ ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
 }
 
 any_to_bytes :: proc "contextless" (val: any) -> []byte {
-	ti := type_info_from_typeid(val.typeid);
+	ti := type_info_of(val.typeid);
 	size := ti != nil ? ti.size : 0;
 	return transmute([]byte)raw.Slice{val.data, size};
 }

+ 17 - 0
src/check_expr.cpp

@@ -3421,6 +3421,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 
 		add_type_info_type(c, t);
 
+		if (is_operand_value(o) && is_type_typeid(t)) {
+			// Okay
+		} else if (o.mode != Addressing_Type) {
+			error(ce->args[0], "Expected a type or typeid for 'type_info_of'");
+			return false;
+		}
+
 		operand->mode = Addressing_Value;
 		operand->type = t_type_info_ptr;
 
@@ -3450,6 +3457,16 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 
 		add_type_info_type(c, t);
 
+		t = base_type(t);
+		if (is_operand_value(o) && are_types_identical(t, t_type_info_ptr)) {
+			add_preload_dependency(c, "__typeid_of");
+		} else if (o.mode != Addressing_Type) {
+			gbString ts = type_to_string(o.type);
+			error(ce->args[0], "Expected a type or type info for 'typeid_of', got %s", ts);
+			gb_string_free(ts);
+			return false;
+		}
+
 		operand->mode = Addressing_Value;
 		operand->type = t_typeid;
 		break;

+ 21 - 4
src/ir.cpp

@@ -4209,13 +4209,30 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv
 	}
 
 	case BuiltinProc_type_info_of: {
-		Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
-		return ir_type_info(proc, t);
+		AstNode *arg = ce->args[0];
+		TypeAndValue tav = type_and_value_of_expr(proc->module->info, arg);
+		if (tav.mode == Addressing_Type) {
+			Type *t = default_type(type_of_expr(proc->module->info, arg));
+			return ir_type_info(proc, t);
+		}
+		GB_ASSERT(is_type_typeid(tav.type));
+		irValue *id = ir_emit_bitcast(proc, ir_build_expr(proc, arg), t_uintptr);
+		return ir_emit_array_ep(proc, ir_global_type_info_data, id);
 	}
 
 	case BuiltinProc_typeid_of: {
-		Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
-		return ir_typeid(proc, t);
+		AstNode *arg = ce->args[0];
+		TypeAndValue tav = type_and_value_of_expr(proc->module->info, arg);
+		if (tav.mode == Addressing_Type) {
+			Type *t = default_type(type_of_expr(proc->module->info, arg));
+			return ir_typeid(proc, t);
+		}
+		Type *t = base_type(tav.type);
+		GB_ASSERT(are_types_identical(t, t_type_info_ptr));
+
+		auto args = array_make<irValue *>(proc->module->allocator, 1);
+		args[0] = ir_emit_conv(proc, ir_build_expr(proc, arg), t_type_info_ptr);
+		return ir_emit_global_call(proc, "__typeid_of", args);
 	}
 
 	case BuiltinProc_len: {