This commit is contained in:
Ginger Bill
2016-09-07 15:15:10 +01:00
parent 61fcfd6f3d
commit 2c4193a242
8 changed files with 260 additions and 106 deletions
+39 -4
View File
@@ -4,7 +4,7 @@
print_type_info_kind :: proc(info: ^Type_Info) {
using Type_Info
match type i : info {
match type info -> i {
case Named: print_string("Named\n")
case Integer: print_string("Integer\n")
case Float: print_string("Float\n")
@@ -23,6 +23,37 @@ print_type_info_kind :: proc(info: ^Type_Info) {
}
}
println :: proc(args: ..any) {
for i := 0; i < len(args); i++ {
arg := args[i]
if i > 0 {
print_string(" ")
}
using Type_Info
match type arg.type_info -> i {
case Named: print_string("Named")
case Integer: print_string("Integer")
case Float: print_string("Float")
case String: print_string("String")
case Boolean: print_string("Boolean")
case Pointer: print_string("Pointer")
case Procedure: print_string("Procedure")
case Array: print_string("Array")
case Slice: print_string("Slice")
case Vector: print_string("Vector")
case Struct: print_string("Struct")
case Union: print_string("Union")
case Raw_Union: print_string("RawUnion")
case Enum: print_string("Enum")
default: print_string("void")
}
}
print_nl()
}
main :: proc() {
i: int
s: struct {
@@ -30,7 +61,11 @@ main :: proc() {
}
p := ^s
print_type_info_kind(type_info(i))
print_type_info_kind(type_info(s))
print_type_info_kind(type_info(p))
a: any = i
println(137, "Hello", 1.23)
// print_type_info_kind(a.type_info)
// print_type_info_kind(type_info(s))
// print_type_info_kind(type_info(p))
}
+2 -10
View File
@@ -18,11 +18,11 @@ Type_Info :: union {
base: ^Type_Info
}
Integer: struct {
bits: int
size: int // in bytes
signed: bool
}
Float: struct {
bits: int
size: int // in bytes
}
String: struct {}
Boolean: struct {}
@@ -49,14 +49,6 @@ Type_Info :: union {
}
}
Any :: struct {
type_info: ^Type_Info
// pointer to the data stored
data: rawptr
}
assume :: proc(cond: bool) #foreign "llvm.assume"
+28 -16
View File
@@ -389,23 +389,7 @@ void add_global_constant(gbAllocator a, String name, Type *type, ExactValue valu
}
Type *t_type_info = NULL;
Type *t_type_info_ptr = NULL;
Type *t_type_info_named = NULL;
Type *t_type_info_integer = NULL;
Type *t_type_info_float = NULL;
Type *t_type_info_string = NULL;
Type *t_type_info_boolean = NULL;
Type *t_type_info_pointer = NULL;
Type *t_type_info_procedure = NULL;
Type *t_type_info_array = NULL;
Type *t_type_info_slice = NULL;
Type *t_type_info_vector = NULL;
Type *t_type_info_struct = NULL;
Type *t_type_info_union = NULL;
Type *t_type_info_raw_union = NULL;
Type *t_type_info_enum = NULL;
void init_universal_scope(void) {
@@ -857,6 +841,7 @@ void check_parsed_files(Checker *c) {
}
}
auto check_global_entity = [](Checker *c, EntityKind kind) {
gb_for_array(i, c->info.entities.entries) {
auto *entry = &c->info.entities.entries[i];
@@ -869,6 +854,33 @@ void check_parsed_files(Checker *c) {
};
check_global_entity(c, Entity_TypeName);
if (t_type_info == NULL) {
String type_info_str = make_string("Type_Info");
Entity **found = map_get(&c->global_scope->elements, hash_string(type_info_str));
GB_ASSERT_MSG(found != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
Entity *e = *found;
t_type_info = e->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
auto *record = &get_base_type(e->type)->Record;
GB_ASSERT(record->field_count == 15);
t_type_info_named = record->fields[ 1]->type;
t_type_info_integer = record->fields[ 2]->type;
t_type_info_float = record->fields[ 3]->type;
t_type_info_string = record->fields[ 4]->type;
t_type_info_boolean = record->fields[ 5]->type;
t_type_info_pointer = record->fields[ 6]->type;
t_type_info_procedure = record->fields[ 7]->type;
t_type_info_array = record->fields[ 8]->type;
t_type_info_slice = record->fields[ 9]->type;
t_type_info_vector = record->fields[10]->type;
t_type_info_struct = record->fields[11]->type;
t_type_info_union = record->fields[12]->type;
t_type_info_raw_union = record->fields[13]->type;
t_type_info_enum = record->fields[14]->type;
}
check_global_entity(c, Entity_Constant);
check_global_entity(c, Entity_Procedure);
check_global_entity(c, Entity_Variable);
+49 -64
View File
@@ -45,6 +45,44 @@ b32 check_is_assignable_to_using_subtype(Type *dst, Type *src) {
return false;
}
void add_type_info_type(Checker *c, Type *t) {
if (t == NULL) {
return;
}
t = default_type(t);
if (map_get(&c->info.type_info_types, hash_pointer(t)) != NULL) {
// Types have already been added
return;
}
map_set(&c->info.type_info_types, hash_pointer(t), t);
Type *bt = get_base_type(t);
switch (bt->kind) {
case Type_Named: add_type_info_type(c, bt->Named.base); break;
case Type_Array: add_type_info_type(c, bt->Array.elem); break;
case Type_Slice: add_type_info_type(c, bt->Slice.elem); break;
case Type_Vector: add_type_info_type(c, bt->Vector.elem); break;
case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break;
case Type_Record: {
switch (bt->Record.kind) {
case TypeRecord_Enum:
add_type_info_type(c, bt->Record.enum_base);
break;
default:
for (isize i = 0; i < bt->Record.field_count; i++) {
Entity *f = bt->Record.fields[i];
add_type_info_type(c, f->type);
}
break;
}
} break;
}
// TODO(bill): Type info for procedures and tuples
// TODO(bill): Remove duplicate identical types efficiently
}
b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argument = false) {
if (operand->mode == Addressing_Invalid ||
type == t_invalid) {
@@ -110,6 +148,13 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
}
}
if (dst == t_any) {
// NOTE(bill): Anything can cast to `Any`
add_type_info_type(c, s);
return true;
}
if (is_argument) {
// NOTE(bill): Polymorphism for subtyping
if (check_is_assignable_to_using_subtype(type, src)) {
@@ -133,11 +178,13 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
if (is_type_untyped(operand->type)) {
Type *target_type = type;
if (type == NULL)
if (type == NULL || is_type_any(type)) {
target_type = default_type(operand->type);
}
convert_to_typed(c, operand, target_type);
if (operand->mode == Addressing_Invalid)
if (operand->mode == Addressing_Invalid) {
return;
}
}
@@ -1900,42 +1947,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
return NULL;
}
void add_type_info_type(Checker *c, Type *t) {
if (t == NULL) {
return;
}
t = default_type(t);
if (map_get(&c->info.type_info_types, hash_pointer(t)) != NULL) {
// Types have already been added
return;
}
map_set(&c->info.type_info_types, hash_pointer(t), t);
Type *bt = get_base_type(t);
switch (bt->kind) {
case Type_Named: add_type_info_type(c, bt->Named.base); break;
case Type_Array: add_type_info_type(c, bt->Array.elem); break;
case Type_Slice: add_type_info_type(c, bt->Slice.elem); break;
case Type_Vector: add_type_info_type(c, bt->Vector.elem); break;
case Type_Pointer: add_type_info_type(c, bt->Pointer.elem); break;
case Type_Record: {
switch (bt->Record.kind) {
case TypeRecord_Enum:
add_type_info_type(c, bt->Record.enum_base);
break;
default:
for (isize i = 0; i < bt->Record.field_count; i++) {
Entity *f = bt->Record.fields[i];
add_type_info_type(c, f->type);
}
break;
}
} break;
}
// TODO(bill): Type info for procedures and tuples
// TODO(bill): Remove duplicate identical types efficiently
}
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
GB_ASSERT(call->kind == AstNode_CallExpr);
ast_node(ce, CallExpr, call);
@@ -2690,32 +2701,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
case BuiltinProc_type_info: {
if (t_type_info == NULL) {
String type_info_str = make_string("Type_Info");
Entity **found = map_get(&c->global_scope->elements, hash_string(type_info_str));
GB_ASSERT_MSG(found != NULL, "Internal Compiler Error: Could not find type declaration for `Type_Info`");
Entity *e = *found;
t_type_info = e->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
auto *record = &get_base_type(e->type)->Record;
GB_ASSERT(record->field_count == 15);
t_type_info_named = record->fields[ 1]->type;
t_type_info_integer = record->fields[ 2]->type;
t_type_info_float = record->fields[ 3]->type;
t_type_info_string = record->fields[ 4]->type;
t_type_info_boolean = record->fields[ 5]->type;
t_type_info_pointer = record->fields[ 6]->type;
t_type_info_procedure = record->fields[ 7]->type;
t_type_info_array = record->fields[ 8]->type;
t_type_info_slice = record->fields[ 9]->type;
t_type_info_vector = record->fields[10]->type;
t_type_info_struct = record->fields[11]->type;
t_type_info_union = record->fields[12]->type;
t_type_info_raw_union = record->fields[13]->type;
t_type_info_enum = record->fields[14]->type;
}
add_type_info_type(c, operand->type);
operand->mode = Addressing_Value;
operand->type = t_type_info_ptr;
+62 -1
View File
@@ -19,6 +19,9 @@ enum BasicKind {
Basic_uint,
Basic_rawptr,
Basic_string,
Basic_any,
Basic_UntypedBool,
Basic_UntypedInteger,
Basic_UntypedFloat,
@@ -26,6 +29,7 @@ enum BasicKind {
Basic_UntypedString,
Basic_UntypedRune,
Basic_Count,
Basic_byte = Basic_u8,
@@ -306,6 +310,7 @@ gb_global Type basic_types[] = {
{0, Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}},
{0, Type_Basic, {Basic_rawptr, BasicFlag_Pointer, STR_LIT("rawptr")}},
{0, Type_Basic, {Basic_string, BasicFlag_String, STR_LIT("string")}},
{0, Type_Basic, {Basic_any, 0, STR_LIT("any")}},
{0, Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}},
{0, Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}},
{0, Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}},
@@ -337,6 +342,7 @@ gb_global Type *t_int = &basic_types[Basic_int];
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_untyped_bool = &basic_types[Basic_UntypedBool];
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
@@ -346,6 +352,25 @@ gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
gb_global Type *t_byte = &basic_type_aliases[Basic_byte];
gb_global Type *t_rune = &basic_type_aliases[Basic_rune];
gb_global Type *t_type_info = NULL;
gb_global Type *t_type_info_ptr = NULL;
gb_global Type *t_type_info_named = NULL;
gb_global Type *t_type_info_integer = NULL;
gb_global Type *t_type_info_float = 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;
gb_global Type *t_type_info_procedure = NULL;
gb_global Type *t_type_info_array = NULL;
gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_enum = NULL;
b32 is_type_named(Type *t) {
if (t->kind == Type_Basic)
@@ -488,6 +513,11 @@ Type *get_enum_base_type(Type *t) {
return t;
}
b32 is_type_any(Type *t) {
t = get_base_type(t);
return (t->kind == Type_Basic && t->Basic.kind == Basic_any);
}
b32 is_type_comparable(Type *t) {
@@ -675,6 +705,9 @@ void selection_add_index(Selection *s, isize index) {
gb_array_append(s->index, index);
}
gb_global Entity *entity_any_type_info = NULL;
gb_global Entity *entity_any_data = NULL;
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
GB_ASSERT(type_ != NULL);
@@ -686,11 +719,39 @@ Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection se
b32 is_ptr = type != type_;
type = get_base_type(type);
if (type->kind == Type_Basic) {
if (type->Basic.kind == Basic_any) {
String type_info_str = make_string("type_info");
String data_str = make_string("data_str");
if (entity_any_type_info == NULL) {
Token token = {Token_Identifier};
token.string = type_info_str;
entity_any_type_info = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false);
}
if (entity_any_data == NULL) {
Token token = {Token_Identifier};
token.string = data_str;
entity_any_data = make_entity_field(gb_heap_allocator(), NULL, token, t_type_info_ptr, false);
}
if (are_strings_equal(field_name, type_info_str)) {
selection_add_index(&sel, 0);
sel.entity = entity_any_type_info;
return sel;
} else if (are_strings_equal(field_name, data_str)) {
selection_add_index(&sel, 1);
sel.entity = entity_any_data;
return sel;
}
}
return sel;
}
if (type->kind != Type_Record) {
return sel;
}
if (is_type) {
if (is_type_union(type)) {
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
+7
View File
@@ -153,6 +153,13 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
case Basic_string: ssa_fprintf(f, "%%..string"); break;
case Basic_uint: ssa_fprintf(f, "i%lld", word_bits); break;
case Basic_int: ssa_fprintf(f, "i%lld", word_bits); break;
case Basic_any:
ssa_fprintf(f, "{");
ssa_print_type(f, s, t_type_info_ptr);
ssa_fprintf(f, ", ");
ssa_print_type(f, s, t_rawptr);
ssa_fprintf(f, "}");
break;
}
break;
case Type_Array:
+71 -8
View File
@@ -1053,9 +1053,26 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S
if (is_type_raw_union(type)) {
type = type->Record.fields[index]->type;
e = ssa_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
} else {
} else if (type->kind == Type_Record) {
type = type->Record.fields[index]->type;
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, type));
} else if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
case Basic_any: {
if (index == 0) {
type = t_type_info_ptr;
} else if (index == 1) {
type = t_rawptr;
}
e = ssa_emit_struct_gep(proc, e, index, make_type_pointer(proc->module->allocator, type));
} break;
default:
GB_PANIC("un-gep-able type");
break;
}
} else {
GB_PANIC("un-gep-able type");
}
}
@@ -1079,9 +1096,26 @@ ssaValue *ssa_emit_deep_field_ev(ssaProcedure *proc, Type *type, ssaValue *e, Se
if (is_type_raw_union(type)) {
type = type->Record.fields[index]->type;
e = ssa_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
} else {
} else if (type->kind == Type_Record) {
type = type->Record.fields[index]->type;
e = ssa_emit_struct_ev(proc, e, index, type);
} else if (type->kind == Type_Basic) {
switch (type->Basic.kind) {
case Basic_any: {
if (index == 0) {
type = t_type_info_ptr;
} else if (index == 1) {
type = t_rawptr;
}
e = ssa_emit_struct_ev(proc, e, index, type);
} break;
default:
GB_PANIC("un-ev-able type");
break;
}
} else {
GB_PANIC("un-ev-able type");
}
}
@@ -1303,12 +1337,17 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
}
if (value->kind == ssaValue_Constant) {
if (dst->kind == Type_Basic) {
if (is_type_any(dst)) {
Type *dt = default_type(src);
ssaValue *default_value = ssa_add_local_generated(proc, dt);
ssa_emit_store(proc, default_value, value);
return ssa_emit_conv(proc, ssa_emit_load(proc, default_value), t_any, is_argument);
} else if (dst->kind == Type_Basic) {
ExactValue ev = value->Constant.value;
if (is_type_float(dst)) {
ev = exact_value_to_float(ev);
} else if (is_type_string(dst)) {
//
// Handled elsewhere
} else if (is_type_integer(dst)) {
ev = exact_value_to_integer(ev);
} else if (is_type_pointer(dst)) {
@@ -1487,6 +1526,33 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
return v;
}
if (is_type_any(dst)) {
ssaValue **found = map_get(&proc->module->members, hash_string(make_string("__type_info_data")));
GB_ASSERT(found != NULL);
ssaValue *type_info_data = *found;
CheckerInfo *info = proc->module->info;
ssaValue *result = ssa_add_local_generated(proc, t_any);
// NOTE(bill): Make copy on stack so I can reference it later
ssaValue *data = ssa_add_local_generated(proc, src_type);
ssa_emit_store(proc, data, value);
data = ssa_emit_conv(proc, data, t_rawptr);
MapFindResult fr = map__find(&info->type_info_types, hash_pointer(src_type));
GB_ASSERT(fr.entry_index >= 0);
ssaValue *ti = ssa_emit_struct_gep(proc, type_info_data, fr.entry_index, t_type_info_ptr);
ssaValue *gep0 = ssa_emit_struct_gep(proc, result, v_zero32, make_type_pointer(proc->module->allocator, t_type_info_ptr));
ssaValue *gep1 = ssa_emit_struct_gep(proc, result, v_one32, make_type_pointer(proc->module->allocator, t_rawptr));
ssa_emit_store(proc, gep0, ti);
ssa_emit_store(proc, gep1, data);
return ssa_emit_load(proc, result);
}
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
@@ -3194,10 +3260,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
ssaBlock *default_block = NULL;
isize case_count = body->list_count;
isize i = 0;
for (AstNode *clause = body->list;
clause != NULL;
clause = clause->next, i++) {
for (AstNode *clause = body->list; clause != NULL; clause = clause->next) {
ast_node(cc, CaseClause, clause);
if (cc->list == NULL) {
+2 -3
View File
@@ -2297,9 +2297,9 @@ AstNode *parse_match_stmt(AstFile *f) {
Token open, close;
if (allow_token(f, Token_type)) {
tag = parse_expr(f, true);
expect_token(f, Token_ArrowRight);
AstNode *var = parse_identifier(f);
expect_token(f, Token_Colon);
tag = parse_simple_stmt(f);
open = expect_token(f, Token_OpenBrace);
AstNode *list = NULL;
@@ -2315,7 +2315,6 @@ AstNode *parse_match_stmt(AstFile *f) {
close = expect_token(f, Token_CloseBrace);
body = make_block_stmt(f, list, list_count, open, close);
tag = convert_stmt_to_expr(f, tag, make_string("type match expression"));
return make_type_match_stmt(f, token, tag, var, body);
} else {
if (f->cursor[0].kind != Token_OpenBrace) {