From c71b547cdeecaa4cc7743be18fcc44f6a9da9c39 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 4 Dec 2016 23:25:52 +0000 Subject: [PATCH] (Crude) Cyclic Type Checking --- build.bat | 2 +- code/demo.odin | 2 - src/checker/checker.c | 34 +++--------- src/checker/decl.c | 123 ++++++++++++++++++----------------------- src/checker/expr.c | 83 +++++++++++----------------- src/checker/stmt.c | 2 +- src/checker/types.c | 125 +++++++++++++++++++++++++++++++++++++----- src/exact_value.c | 2 +- 8 files changed, 209 insertions(+), 164 deletions(-) diff --git a/build.bat b/build.bat index 84b99c3a2..2fb8b9bc7 100644 --- a/build.bat +++ b/build.bat @@ -16,7 +16,7 @@ if %release_mode% EQU 0 ( rem Debug ) set compiler_warnings= ^ - -we4002 -we4013 -we4024 -we4047 -we4133 -we4706 ^ + -we4002 -we4013 -we4020 -we4024 -we4029 -we4031 -we4047 -we4133 -we4706 ^ -wd4100 -wd4101 -wd4127 -wd4189 ^ -wd4201 -wd4204 -wd4244 ^ -wd4306 ^ diff --git a/code/demo.odin b/code/demo.odin index 88b5c5064..d01db00ac 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,8 +1,6 @@ // #import "game.odin"; #import "fmt.odin"; -x := type_info(int); - main :: proc() { fmt.println(123); } diff --git a/src/checker/checker.c b/src/checker/checker.c index 60dea3be0..cf95c146b 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -269,33 +269,9 @@ typedef struct Checker { bool done_preload; } Checker; -typedef struct CycleChecker { - Array(Entity *) path; // Entity_TypeName -} CycleChecker; - -CycleChecker *cycle_checker_add(CycleChecker *cc, Entity *e) { - if (cc == NULL) { - return NULL; - } - if (cc->path.e == NULL) { - array_init(&cc->path, heap_allocator()); - } - if (e != NULL && e->kind == Entity_TypeName) { - array_add(&cc->path, e); - } - return cc; -} - -void cycle_checker_destroy(CycleChecker *cc) { - if (cc != NULL && cc->path.e != NULL) { - array_free(&cc->path); - } -} - - void init_declaration_info(DeclInfo *d, Scope *scope) { d->scope = scope; map_bool_init(&d->deps, heap_allocator()); @@ -1095,7 +1071,7 @@ void check_all_global_entities(Checker *c) { Scope *prev_scope = c->context.scope; c->context.scope = d->scope; - check_entity_decl(c, e, d, NULL, NULL); + check_entity_decl(c, e, d, NULL); if (d->scope->is_init && !c->done_preload) { @@ -1488,6 +1464,14 @@ void check_parsed_files(Checker *c) { add_type_info_type(c, t); } } + + for_array(i, c->info.definitions.entries) { + Entity *e = c->info.definitions.entries.e[i].value; + if (e->kind == Entity_TypeName) { + i64 align = type_align_of(c->sizes, c->allocator, e->type); + GB_ASSERT(align > 0); + } + } } diff --git a/src/checker/decl.c b/src/checker/decl.c index ef227e610..098abfe20 100644 --- a/src/checker/decl.c +++ b/src/checker/decl.c @@ -1,10 +1,6 @@ bool check_is_terminating(AstNode *node); void check_stmt (Checker *c, AstNode *node, u32 flags); void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags); -void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker); -void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr); -void check_proc_decl (Checker *c, Entity *e, DeclInfo *d); -void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr); // NOTE(bill): `content_name` is for debugging and error messages Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) { @@ -103,56 +99,6 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra } - -void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) { - if (e->type != NULL) { - return; - } - - if (d == NULL) { - DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); - if (found) { - d = *found; - } else { - e->type = t_invalid; - set_base_type(named_type, t_invalid); - return; - // GB_PANIC("`%.*s` should been declared!", LIT(e->token.string)); - } - } - -#if 0 - if (e->kind == Entity_Procedure) { - check_proc_decl(c, e, d); - return; - } -#endif - CheckerContext prev = c->context; - c->context.scope = d->scope; - c->context.decl = d; - - switch (e->kind) { - case Entity_Constant: - check_const_decl(c, e, d->type_expr, d->init_expr); - break; - case Entity_Variable: - check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); - break; - case Entity_TypeName: - check_type_decl(c, e, d->type_expr, named_type, cycle_checker); - break; -#if 1 - case Entity_Procedure: - check_proc_decl(c, e, d); - break; -#endif - } - - c->context = prev; -} - - - void check_var_decl_node(Checker *c, AstNode *node) { ast_node(vd, VarDecl, node); isize entity_count = vd->names.count; @@ -192,7 +138,7 @@ void check_var_decl_node(Checker *c, AstNode *node) { Type *init_type = NULL; if (vd->type) { - init_type = check_type_extra(c, vd->type, NULL, NULL); + init_type = check_type_extra(c, vd->type, NULL); if (init_type == NULL) init_type = t_invalid; } @@ -292,7 +238,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e check_init_constant(c, e, &operand); } -void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker) { +void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { GB_ASSERT(e->type == NULL); Type *named = make_type_named(c->allocator, e->token.string, NULL, e); named->Named.type_name = e; @@ -301,19 +247,13 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle } e->type = named; - CycleChecker local_cycle_checker = {0}; - if (cycle_checker == NULL) { - cycle_checker = &local_cycle_checker; - } + // gb_printf_err("%.*s %p\n", LIT(e->token.string), e); - Type *bt = check_type_extra(c, type_expr, named, cycle_checker_add(cycle_checker, e)); - named->Named.base = bt; - named->Named.base = base_type(named->Named.base); + Type *bt = check_type_extra(c, type_expr, named); + named->Named.base = base_type(bt); if (named->Named.base == t_invalid) { // gb_printf("check_type_decl: %s\n", type_to_string(named)); } - - cycle_checker_destroy(&local_cycle_checker); } @@ -458,12 +398,14 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } e->flags |= EntityFlag_Visited; - if (type_expr != NULL) - e->type = check_type_extra(c, type_expr, NULL, NULL); + if (type_expr != NULL) { + e->type = check_type_extra(c, type_expr, NULL); + } if (init_expr == NULL) { - if (type_expr == NULL) + if (type_expr == NULL) { e->type = t_invalid; + } return; } @@ -475,8 +417,9 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } if (type_expr != NULL) { - for (isize i = 0; i < entity_count; i++) + for (isize i = 0; i < entity_count; i++) { entities[i]->type = e->type; + } } AstNodeArray inits; @@ -485,6 +428,48 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count check_init_variables(c, entities, entity_count, inits, str_lit("variable declaration")); } + +void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { + if (e->type != NULL) { + return; + } + + if (d == NULL) { + DeclInfo **found = map_decl_info_get(&c->info.entities, hash_pointer(e)); + if (found) { + d = *found; + } else { + e->type = t_invalid; + set_base_type(named_type, t_invalid); + return; + // GB_PANIC("`%.*s` should been declared!", LIT(e->token.string)); + } + } + + CheckerContext prev = c->context; + c->context.scope = d->scope; + c->context.decl = d; + + switch (e->kind) { + case Entity_Constant: + check_const_decl(c, e, d->type_expr, d->init_expr); + break; + case Entity_Variable: + check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr); + break; + case Entity_TypeName: + check_type_decl(c, e, d->type_expr, named_type); + break; + case Entity_Procedure: + check_proc_decl(c, e, d); + break; + } + + c->context = prev; +} + + + void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) { GB_ASSERT(body->kind == AstNode_BlockStmt); diff --git a/src/checker/expr.c b/src/checker/expr.c index 501ccaa64..d0414e2fc 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -2,20 +2,20 @@ void check_expr (Checker *c, Operand *operand, AstNode *expre void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); -Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type, CycleChecker *cycle_checker); +Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type); Type * check_type (Checker *c, AstNode *expression); -void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker); +void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); Entity * check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); void convert_to_typed (Checker *c, Operand *operand, Type *target_type, i32 level); gbString expr_to_string (AstNode *expression); -void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type, CycleChecker *cycle_checker); +void check_entity_decl (Checker *c, Entity *e, DeclInfo *decl, Type *named_type); void check_proc_body (Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body); void update_expr_type (Checker *c, AstNode *e, Type *type, bool final); gb_inline Type *check_type(Checker *c, AstNode *expression) { - return check_type_extra(c, expression, NULL, NULL); + return check_type_extra(c, expression, NULL); } @@ -225,13 +225,13 @@ void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size, Delay for_array(i, delayed_entities) { DelayedEntity delayed = delayed_entities.e[i]; if (delayed.entity->kind == Entity_TypeName) { - check_entity_decl(c, delayed.entity, delayed.decl, NULL, NULL); + check_entity_decl(c, delayed.entity, delayed.decl, NULL); } } for_array(i, delayed_entities) { DelayedEntity delayed = delayed_entities.e[i]; if (delayed.entity->kind == Entity_Constant) { - check_entity_decl(c, delayed.entity, delayed.decl, NULL, NULL); + check_entity_decl(c, delayed.entity, delayed.decl, NULL); } } @@ -460,7 +460,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Entity **fields, isize field_count, Entity **other_fields, isize other_field_count, - CycleChecker *cycle_checker, String context) { + String context) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); MapEntity entity_map = {0}; @@ -486,7 +486,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, } ast_node(vd, VarDecl, decl); - Type *base_type = check_type_extra(c, vd->type, NULL, cycle_checker); + Type *base_type = check_type_extra(c, vd->type, NULL); for_array(name_index, vd->names) { AstNode *name = vd->names.e[name_index]; @@ -526,7 +526,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, } ast_node(vd, VarDecl, decl); - Type *type = check_type_extra(c, vd->type, NULL, cycle_checker); + Type *type = check_type_extra(c, vd->type, NULL); if (vd->is_using) { if (vd->names.count > 1) { @@ -633,7 +633,7 @@ GB_COMPARE_PROC(cmp_struct_entity_size) { return xa > ya ? -1 : xa < ya; } -void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecker *cycle_checker) { +void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { GB_ASSERT(is_type_struct(struct_type)); ast_node(st, StructType, node); @@ -659,7 +659,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity **other_fields = gb_alloc_array(c->allocator, Entity *, other_field_count); - check_fields(c, node, st->decls, fields, field_count, other_fields, other_field_count, cycle_checker, str_lit("struct")); + check_fields(c, node, st->decls, fields, field_count, other_fields, other_field_count, str_lit("struct")); struct_type->Record.struct_is_packed = st->is_packed; struct_type->Record.struct_is_ordered = st->is_ordered; @@ -694,7 +694,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke type_set_offsets(c->sizes, c->allocator, struct_type); } -void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { +void check_union_type(Checker *c, Type *union_type, AstNode *node) { GB_ASSERT(is_type_union(union_type)); ast_node(ut, UnionType, node); @@ -720,7 +720,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity **other_fields = gb_alloc_array(c->allocator, Entity *, other_field_count); - check_fields(c, node, ut->decls, fields, field_count, other_fields, other_field_count, cycle_checker, str_lit("union")); + check_fields(c, node, ut->decls, fields, field_count, other_fields, other_field_count, str_lit("union")); union_type->Record.fields = fields; union_type->Record.field_count = field_count; @@ -728,7 +728,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker union_type->Record.other_field_count = other_field_count; } -void check_raw_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { +void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { GB_ASSERT(node->kind == AstNode_RawUnionType); GB_ASSERT(is_type_raw_union(union_type)); ast_node(ut, RawUnionType, node); @@ -755,7 +755,7 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node, CycleChec Entity **fields = gb_alloc_array(c->allocator, Entity *, field_count); Entity **other_fields = gb_alloc_array(c->allocator, Entity *, other_field_count); - check_fields(c, node, ut->decls, fields, field_count, other_fields, other_field_count, cycle_checker, str_lit("raw union")); + check_fields(c, node, ut->decls, fields, field_count, other_fields, other_field_count, str_lit("raw union")); union_type->Record.fields = fields; union_type->Record.field_count = field_count; @@ -1017,7 +1017,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } -void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, CycleChecker *cycle_checker) { +void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -1037,13 +1037,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl } add_entity_use(c, n, e); - // CycleChecker local_cycle_checker = {0}; - // if (cycle_checker == NULL) { - // cycle_checker = &local_cycle_checker; - // } - // defer (cycle_checker_destroy(&local_cycle_checker)); - - check_entity_decl(c, e, NULL, named_type, cycle_checker); + check_entity_decl(c, e, NULL, named_type); if (e->type == NULL) { compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string)); @@ -1085,23 +1079,8 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl case Entity_TypeName: { o->mode = Addressing_Type; -#if 0 +#if 1 // TODO(bill): Fix cyclical dependancy checker - if (cycle_checker != NULL) { - for_array(i, cycle_checker->path) { - Entity *prev = cycle_checker->path[i]; - if (prev == e) { - error(e->token, "Illegal declaration cycle for %.*s", LIT(e->token.string)); - for (isize j = i; j < gb_array_count(cycle_checker->path); j++) { - Entity *ref = cycle_checker->path[j]; - error(ref->token, "\t%.*s refers to", LIT(ref->token.string)); - } - error(e->token, "\t%.*s", LIT(e->token.string)); - type = t_invalid; - break; - } - } - } #endif } break; @@ -1161,7 +1140,7 @@ i64 check_array_count(Checker *c, AstNode *e) { return 0; } -Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_checker) { +Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { ExactValue null_value = {ExactValue_Invalid}; Type *type = NULL; gbString err_str = NULL; @@ -1169,7 +1148,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c switch (e->kind) { case_ast_node(i, Ident, e); Operand o = {0}; - check_identifier(c, &o, e, named_type, cycle_checker); + check_identifier(c, &o, e, named_type); switch (o.mode) { case Addressing_Invalid: @@ -1212,7 +1191,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c case_end; case_ast_node(pe, ParenExpr, e); - type = check_type_extra(c, pe->expr, named_type, cycle_checker); + type = check_type_extra(c, pe->expr, named_type); goto end; case_end; @@ -1240,7 +1219,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c case_ast_node(at, ArrayType, e); if (at->count != NULL) { - Type *elem = check_type_extra(c, at->elem, NULL, cycle_checker); + Type *elem = check_type_extra(c, at->elem, NULL); type = make_type_array(c->allocator, elem, check_array_count(c, at->count)); } else { Type *elem = check_type(c, at->elem); @@ -1266,7 +1245,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c type = make_type_struct(c->allocator); set_base_type(named_type, type); check_open_scope(c, e); - check_struct_type(c, type, e, cycle_checker); + check_struct_type(c, type, e); check_close_scope(c); type->Record.node = e; goto end; @@ -1276,7 +1255,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c type = make_type_union(c->allocator); set_base_type(named_type, type); check_open_scope(c, e); - check_union_type(c, type, e, cycle_checker); + check_union_type(c, type, e); check_close_scope(c); type->Record.node = e; goto end; @@ -1286,7 +1265,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type, CycleChecker *c type = make_type_raw_union(c->allocator); set_base_type(named_type, type); check_open_scope(c, e); - check_raw_union_type(c, type, e, cycle_checker); + check_raw_union_type(c, type, e); check_close_scope(c); type->Record.node = e; goto end; @@ -1333,7 +1312,9 @@ end: if (is_type_named(type)) { if (type->Named.base == NULL) { - error_node(e, "Invalid type definition"); + gbString name = type_to_string(type); + error_node(e, "Invalid type definition of %s", name); + gb_string_free(name); type->Named.base = t_invalid; } } @@ -1341,7 +1322,9 @@ end: if (is_type_typed(type)) { add_type_and_value(&c->info, e, Addressing_Type, type, null_value); } else { - error_node(e, "Invalid type definition"); + gbString name = type_to_string(type); + error_node(e, "Invalid type definition of %s", name); + gb_string_free(name); type = t_invalid; } set_base_type(named_type, type); @@ -2581,7 +2564,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { goto error; } if (entity->type == NULL) { // Not setup yet - check_entity_decl(c, entity, NULL, NULL, NULL); + check_entity_decl(c, entity, NULL, NULL); } GB_ASSERT(entity->type != NULL); @@ -3890,7 +3873,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_end; case_ast_node(i, Ident, node); - check_identifier(c, o, node, type_hint, NULL); + check_identifier(c, o, node, type_hint); case_end; case_ast_node(bl, BasicLit, node); diff --git a/src/checker/stmt.c b/src/checker/stmt.c index 8edb09062..f944fd255 100644 --- a/src/checker/stmt.c +++ b/src/checker/stmt.c @@ -1102,7 +1102,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { d->proc_decl = node; add_entity_and_decl_info(c, pd->name, e, d); - check_entity_decl(c, e, d, NULL, NULL); + check_entity_decl(c, e, d, NULL); #endif case_end; } diff --git a/src/checker/types.c b/src/checker/types.c index 1d7ce2067..ee4a65262 100644 --- a/src/checker/types.c +++ b/src/checker/types.c @@ -302,6 +302,9 @@ Type *base_type(Type *t) { if (t == NULL || t->kind != Type_Named) { break; } + if (t == t->Named.base) { + return t_invalid; + } t = t->Named.base; } return t; @@ -1037,11 +1040,66 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } +typedef struct TypePath { + Array(Type *) path; // Entity_TypeName; + bool failure; +} TypePath; + +void type_path_init(TypePath *tp) { + // TODO(bill): Use an allocator that uses a backing array if it can and then use alternative allocator when exhausted + array_init(&tp->path, heap_allocator()); +} + +void type_path_free(TypePath *tp) { + array_free(&tp->path); +} + +TypePath *type_path_push(TypePath *tp, Type *t) { + GB_ASSERT(tp != NULL); + + for_array(i, tp->path) { + if (tp->path.e[i] == t) { + // TODO(bill): + GB_ASSERT(is_type_named(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 + for (isize j = 0; j < tp->path.count; j++) { + Type *t = tp->path.e[j]; + GB_ASSERT(is_type_named(t)); + 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 + error(e->token, "\t%.*s", LIT(t->Named.name)); + tp->failure = true; + + // NOTE(bill): Just quit immediately + // TODO(bill): Try and solve this gracefully + gb_exit(1); + } + } + + if (!tp->failure) { + array_add(&tp->path, t); + } + return tp; +} + +void type_path_pop(TypePath *tp) { + if (tp != NULL) { + array_pop(&tp->path); + } +} + + i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t); i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index); +i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path); + i64 align_formula(i64 size, i64 align) { if (align > 0) { i64 result = size + align-1; @@ -1050,12 +1108,25 @@ i64 align_formula(i64 size, i64 align) { return size; } + + i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { + i64 align; + TypePath path = {0}; + type_path_init(&path); + align = type_align_of_internal(s, allocator, t, &path); + type_path_free(&path); + return align; +} + +#define FAILURE_ALIGNMENT (-1) + +i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypePath *path) { t = base_type(t); switch (t->kind) { case Type_Array: - return type_align_of(s, allocator, t->Array.elem); + return type_align_of_internal(s, allocator, t->Array.elem, path); case Type_Vector: { i64 size = type_size_of(s, allocator, t->Vector.elem); i64 count = gb_max(prev_pow2(t->Vector.count), 1); @@ -1066,7 +1137,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case Type_Tuple: { i64 max = 1; for (isize i = 0; i < t->Tuple.variable_count; i++) { - i64 align = type_align_of(s, allocator, t->Tuple.variables[i]->type); + i64 align = type_align_of_internal(s, allocator, t->Tuple.variables[i]->type, path); if (max < align) { max = align; } @@ -1075,7 +1146,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } break; case Type_Maybe: - return gb_max(type_align_of(s, allocator, t->Maybe.elem), type_align_of(s, allocator, t_bool)); + return gb_max(type_align_of_internal(s, allocator, t->Maybe.elem, path), type_align_of_internal(s, allocator, t_bool, path)); case Type_Record: { switch (t->Record.kind) { @@ -1084,23 +1155,41 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { // TODO(bill): What is this supposed to be? if (t->Record.struct_is_packed) { i64 max = s.word_size; - for (isize i = 1; i < t->Record.field_count; i++) { - // NOTE(bill): field zero is null - i64 align = type_align_of(s, allocator, t->Record.fields[i]->type); + for (isize i = 0; i < t->Record.field_count; i++) { + Type *field_type = t->Record.fields[i]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(s, allocator, field_type, path); + type_path_pop(path); if (max < align) { max = align; } } return max; } - return type_align_of(s, allocator, t->Record.fields[0]->type); + Type *field_type = t->Record.fields[0]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(s, allocator, field_type, path); + type_path_pop(path); + return align; } break; case TypeRecord_Union: { i64 max = 1; + // NOTE(bill): field zero is null for (isize i = 1; i < t->Record.field_count; i++) { - // NOTE(bill): field zero is null - i64 align = type_align_of(s, allocator, t->Record.fields[i]->type); + Type *field_type = t->Record.fields[i]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(s, allocator, field_type, path); + type_path_pop(path); if (max < align) { max = align; } @@ -1110,7 +1199,13 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case TypeRecord_RawUnion: { i64 max = 1; for (isize i = 0; i < t->Record.field_count; i++) { - i64 align = type_align_of(s, allocator, t->Record.fields[i]->type); + Type *field_type = t->Record.fields[i]->type; + type_path_push(path, field_type); + if (path->failure) { + return FAILURE_ALIGNMENT; + } + i64 align = type_align_of_internal(s, allocator, field_type, path); + type_path_pop(path); if (max < align) { max = align; } @@ -1118,7 +1213,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { return max; } break; case TypeRecord_Enum: - return type_align_of(s, allocator, t->Record.enum_base); + return type_align_of_internal(s, allocator, t->Record.enum_base, path); } } break; } @@ -1232,9 +1327,9 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { if (count == 0) { return 0; } + i64 align = type_align_of(s, allocator, t); type_set_offsets(s, allocator, t); i64 size = t->Tuple.offsets[count-1] + type_size_of(s, allocator, t->Tuple.variables[count-1]->type); - i64 align = type_align_of(s, allocator, t); return align_formula(size, align); } break; @@ -1245,14 +1340,15 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { if (count == 0) { return 0; } + i64 align = type_align_of(s, allocator, t); type_set_offsets(s, allocator, t); i64 size = t->Record.struct_offsets[count-1] + type_size_of(s, allocator, t->Record.fields[count-1]->type); - i64 align = type_align_of(s, allocator, t); return align_formula(size, align); } break; case TypeRecord_Union: { i64 count = t->Record.field_count; + i64 align = type_align_of(s, allocator, t); i64 max = 0; // NOTE(bill): Zeroth field is invalid for (isize i = 1; i < count; i++) { @@ -1262,7 +1358,6 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } } // NOTE(bill): Align to int - i64 align = type_align_of(s, allocator, t); isize size = align_formula(max, s.word_size); size += type_size_of(s, allocator, t_int); return align_formula(size, align); @@ -1270,6 +1365,7 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case TypeRecord_RawUnion: { i64 count = t->Record.field_count; + i64 align = type_align_of(s, allocator, t); i64 max = 0; for (isize i = 0; i < count; i++) { i64 size = type_size_of(s, allocator, t->Record.fields[i]->type); @@ -1278,7 +1374,6 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } } // TODO(bill): Is this how it should work? - i64 align = type_align_of(s, allocator, t); return align_formula(max, align); } break; diff --git a/src/exact_value.c b/src/exact_value.c index 46184bb72..141851546 100644 --- a/src/exact_value.c +++ b/src/exact_value.c @@ -58,7 +58,7 @@ ExactValue make_exact_value_integer_from_string(String string) { // TODO(bill): Allow for numbers with underscores in them ExactValue result = {ExactValue_Integer}; i32 base = 10; - if (string.text[0] == '0') { + if (string.len > 2 && string.text[0] == '0') { switch (string.text[1]) { case 'b': base = 2; break; case 'o': base = 8; break;