Fix cyclic type checking bug

This commit is contained in:
gingerBill
2017-11-05 23:38:09 +00:00
parent d4f335d068
commit 9df3a94d33
2 changed files with 44 additions and 44 deletions
+1 -1
View File
@@ -781,7 +781,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
if hash do write_string(fi.buf, ",\n"); if hash do write_string(fi.buf, ",\n");
} }
if hash do for in 0..fi.indent do write_byte(fi.buf, '\t'); if hash do for in 0..indent do write_byte(fi.buf, '\t');
write_byte(fi.buf, '}'); write_byte(fi.buf, '}');
case: case:
+43 -43
View File
@@ -1731,7 +1731,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
struct TypePath { struct TypePath {
Array<Type *> path; // Entity_TypeName; Array<Entity *> path; // Entity_TypeName;
bool failure; bool failure;
}; };
@@ -1748,38 +1748,37 @@ void type_path_print_illegal_cycle(TypePath *tp, isize start_index) {
GB_ASSERT(tp != nullptr); GB_ASSERT(tp != nullptr);
GB_ASSERT(start_index < tp->path.count); GB_ASSERT(start_index < tp->path.count);
Type *t = tp->path[start_index]; Entity *e = tp->path[start_index];
GB_ASSERT(t != nullptr); GB_ASSERT(e != nullptr);
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(e->token.string));
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t));
Entity *e = t->Named.type_name;
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(t->Named.name));
// NOTE(bill): Print cycle, if it's deep enough // NOTE(bill): Print cycle, if it's deep enough
for (isize j = start_index; j < tp->path.count; j++) { for (isize j = start_index; j < tp->path.count; j++) {
Type *t = tp->path[j]; Entity *e = tp->path[j];
GB_ASSERT_MSG(is_type_named(t), "%s", type_to_string(t)); error(e->token, "\t%.*s refers to", LIT(e->token.string));
Entity *e = t->Named.type_name;
error(e->token, "\t%.*s refers to", LIT(t->Named.name));
} }
// NOTE(bill): This will only print if the path count > 1 // NOTE(bill): This will only print if the path count > 1
error(e->token, "\t%.*s", LIT(t->Named.name)); error(e->token, "\t%.*s", LIT(e->token.string));
tp->failure = true; tp->failure = true;
t->failure = true; e->type->failure = true;
base_type(e->type)->failure = true;
} }
TypePath *type_path_push(TypePath *tp, Type *t) { bool type_path_push(TypePath *tp, Type *t) {
GB_ASSERT(tp != nullptr); GB_ASSERT(tp != nullptr);
if (t->kind != Type_Named) {
return false;
}
Entity *e = t->Named.type_name;
for (isize i = 0; i < tp->path.count; i++) { for (isize i = 0; i < tp->path.count; i++) {
if (tp->path[i] == t) { Entity *p = tp->path[i];
if (p == e) {
type_path_print_illegal_cycle(tp, i); type_path_print_illegal_cycle(tp, i);
} }
} }
if (!tp->failure && is_type_named(t)) { array_add(&tp->path, e);
array_add(&tp->path, t); return true;
}
return tp;
} }
void type_path_pop(TypePath *tp) { void type_path_pop(TypePath *tp) {
@@ -1830,6 +1829,7 @@ i64 type_align_of(gbAllocator allocator, Type *t) {
i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
GB_ASSERT(path != nullptr);
if (t->failure) { if (t->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
@@ -1853,14 +1853,26 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case Type_Array: { case Type_Array: {
Type *elem = t->Array.elem; Type *elem = t->Array.elem;
type_path_push(path, elem); bool pop = type_path_push(path, elem);
if (path->failure) { if (path->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
i64 align = type_align_of_internal(allocator, t->Array.elem, path); i64 align = type_align_of_internal(allocator, t->Array.elem, path);
type_path_pop(path); if (pop) type_path_pop(path);
return align; return align;
} }
case Type_Vector: {
Type *elem = t->Vector.elem;
bool pop = type_path_push(path, elem);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
if (pop) type_path_pop(path);
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
i64 total = size * count;
return gb_clamp(total, 1, build_context.max_align);
} break;
case Type_DynamicArray: case Type_DynamicArray:
// data, count, capacity, allocator // data, count, capacity, allocator
@@ -1869,18 +1881,6 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
case Type_Slice: case Type_Slice:
return build_context.word_size; return build_context.word_size;
case Type_Vector: {
Type *elem = t->Vector.elem;
type_path_push(path, elem);
if (path->failure) {
return FAILURE_ALIGNMENT;
}
i64 size = type_size_of_internal(allocator, t->Vector.elem, path);
type_path_pop(path);
i64 count = gb_max(prev_pow2(t->Vector.count), 1);
i64 total = size * count;
return gb_clamp(total, 1, build_context.max_align);
} break;
case Type_Tuple: { case Type_Tuple: {
i64 max = 1; i64 max = 1;
@@ -1911,12 +1911,12 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
i64 max = union_tag_size(t); i64 max = union_tag_size(t);
for_array(i, t->Union.variants) { for_array(i, t->Union.variants) {
Type *variant = t->Union.variants[i]; Type *variant = t->Union.variants[i];
type_path_push(path, variant); bool pop = type_path_push(path, variant);
if (path->failure) { if (path->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
i64 align = type_align_of_internal(allocator, variant, path); i64 align = type_align_of_internal(allocator, variant, path);
type_path_pop(path); if (pop) type_path_pop(path);
if (max < align) { if (max < align) {
max = align; max = align;
} }
@@ -1932,12 +1932,12 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
i64 max = 1; i64 max = 1;
for_array(i, t->Struct.fields) { for_array(i, t->Struct.fields) {
Type *field_type = t->Struct.fields[i]->type; Type *field_type = t->Struct.fields[i]->type;
type_path_push(path, field_type); bool pop = type_path_push(path, field_type);
if (path->failure) { if (path->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
i64 align = type_align_of_internal(allocator, field_type, path); i64 align = type_align_of_internal(allocator, field_type, path);
type_path_pop(path); if (pop) type_path_pop(path);
if (max < align) { if (max < align) {
max = align; max = align;
} }
@@ -1948,10 +1948,10 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
// NOTE(bill): Check the fields to check for cyclic definitions // NOTE(bill): Check the fields to check for cyclic definitions
for_array(i, t->Struct.fields) { for_array(i, t->Struct.fields) {
Type *field_type = t->Struct.fields[i]->type; Type *field_type = t->Struct.fields[i]->type;
type_path_push(path, field_type); bool pop = type_path_push(path, field_type);
if (path->failure) return FAILURE_ALIGNMENT; if (path->failure) return FAILURE_ALIGNMENT;
i64 align = type_align_of_internal(allocator, field_type, path); i64 align = type_align_of_internal(allocator, field_type, path);
type_path_pop(path); if (pop) type_path_pop(path);
if (max < align) { if (max < align) {
max = align; max = align;
} }
@@ -2033,12 +2033,12 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
switch (t->kind) { switch (t->kind) {
case Type_Named: { case Type_Named: {
type_path_push(path, t); bool pop = type_path_push(path, t);
if (path->failure) { if (path->failure) {
return FAILURE_ALIGNMENT; return FAILURE_ALIGNMENT;
} }
i64 size = type_size_of_internal(allocator, t->Named.base, path); i64 size = type_size_of_internal(allocator, t->Named.base, path);
type_path_pop(path); if (pop) type_path_pop(path);
return size; return size;
} break; } break;
@@ -2080,12 +2080,12 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (count == 0) { if (count == 0) {
return 0; return 0;
} }
type_path_push(path, t->Vector.elem); bool pop = type_path_push(path, t->Vector.elem);
if (path->failure) { if (path->failure) {
return FAILURE_SIZE; return FAILURE_SIZE;
} }
bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path); bit_size = 8*type_size_of_internal(allocator, t->Vector.elem, path);
type_path_pop(path); if (pop) type_path_pop(path);
if (is_type_boolean(t->Vector.elem)) { if (is_type_boolean(t->Vector.elem)) {
bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1` bit_size = 1; // NOTE(bill): LLVM can store booleans as 1 bit because a boolean _is_ an `i1`
// Silly LLVM spec // Silly LLVM spec