mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Minimal Dependency Map: Only build what is needed
This commit is contained in:
+112
-49
@@ -104,6 +104,7 @@ struct ProcedureInfo {
|
||||
DeclInfo *decl;
|
||||
Type * type; // Type_Procedure
|
||||
AstNode * body; // AstNode_BlockStatement
|
||||
u32 tags;
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
@@ -213,6 +214,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
struct CheckerContext {
|
||||
Scope *scope;
|
||||
DeclInfo *decl;
|
||||
u32 stmt_state_flags;
|
||||
};
|
||||
|
||||
// NOTE(bill): Symbol tables
|
||||
@@ -321,6 +323,7 @@ void check_open_scope(Checker *c, AstNode *node) {
|
||||
scope->is_proc = true;
|
||||
}
|
||||
c->context.scope = scope;
|
||||
c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
}
|
||||
|
||||
void check_close_scope(Checker *c) {
|
||||
@@ -528,7 +531,6 @@ void destroy_checker_info(CheckerInfo *i) {
|
||||
map_destroy(&i->foreign_procs);
|
||||
map_destroy(&i->type_info_map);
|
||||
map_destroy(&i->files);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -574,14 +576,16 @@ TypeAndValue *type_and_value_of_expression(CheckerInfo *i, AstNode *expression)
|
||||
|
||||
|
||||
Entity *entity_of_ident(CheckerInfo *i, AstNode *identifier) {
|
||||
GB_ASSERT(identifier->kind == AstNode_Ident);
|
||||
Entity **found = map_get(&i->definitions, hash_pointer(identifier));
|
||||
if (found)
|
||||
return *found;
|
||||
|
||||
found = map_get(&i->uses, hash_pointer(identifier));
|
||||
if (found)
|
||||
return *found;
|
||||
if (identifier->kind == AstNode_Ident) {
|
||||
Entity **found = map_get(&i->definitions, hash_pointer(identifier));
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
found = map_get(&i->uses, hash_pointer(identifier));
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -611,8 +615,9 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode
|
||||
|
||||
if (mode == Addressing_Constant) {
|
||||
GB_ASSERT(value.kind != ExactValue_Invalid);
|
||||
GB_ASSERT_MSG(type != t_invalid || is_type_constant_type(type),
|
||||
"type: %s", type_to_string(type));
|
||||
if (!(type != t_invalid || is_type_constant_type(type))) {
|
||||
compiler_error("add_type_and_value - invalid type: %s", type_to_string(type));
|
||||
}
|
||||
}
|
||||
|
||||
TypeAndValue tv = {};
|
||||
@@ -666,21 +671,19 @@ b32 add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) {
|
||||
void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
|
||||
GB_ASSERT(identifier != NULL);
|
||||
GB_ASSERT(identifier->kind == AstNode_Ident);
|
||||
HashKey key = hash_pointer(identifier);
|
||||
map_set(&i->uses, key, entity);
|
||||
|
||||
if (entity != NULL && entity->kind == Entity_ImportName) {
|
||||
entity->ImportName.used = true;
|
||||
if (identifier->kind != AstNode_Ident) {
|
||||
return;
|
||||
}
|
||||
map_set(&c->info.uses, hash_pointer(identifier), entity);
|
||||
add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
|
||||
}
|
||||
|
||||
|
||||
void add_file_entity(Checker *c, Scope *file_scope, AstNode *identifier, Entity *e, DeclInfo *d) {
|
||||
void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d) {
|
||||
GB_ASSERT(identifier->Ident.string == e->token.string);
|
||||
add_entity(c, file_scope, identifier, e);
|
||||
add_entity(c, e->scope, identifier, e);
|
||||
map_set(&c->info.entities, hash_pointer(e), d);
|
||||
}
|
||||
|
||||
@@ -721,7 +724,7 @@ void add_type_info_type(Checker *c, Type *t) {
|
||||
return;
|
||||
}
|
||||
|
||||
Type *bt = get_base_type(t);
|
||||
Type *bt = base_type(t);
|
||||
switch (bt->kind) {
|
||||
case Type_Basic: {
|
||||
if (bt->Basic.kind == Basic_string) {
|
||||
@@ -778,13 +781,14 @@ void add_type_info_type(Checker *c, Type *t) {
|
||||
}
|
||||
|
||||
|
||||
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *decl, Type *type, AstNode *body, u32 tags) {
|
||||
ProcedureInfo info = {};
|
||||
info.file = file;
|
||||
info.token = token;
|
||||
info.decl = decl;
|
||||
info.type = type;
|
||||
info.body = body;
|
||||
info.tags = tags;
|
||||
gb_array_append(c->procs, info);
|
||||
}
|
||||
|
||||
@@ -808,6 +812,50 @@ void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||
TokenPos zero_pos = {};
|
||||
global_error_collector.prev = zero_pos;
|
||||
c->curr_ast_file = file;
|
||||
c->context.decl = file->decl_info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void add_dependency_to_map(Map<Entity *> *map, CheckerInfo *info, Entity *node) {
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
if (map_get(map, hash_pointer(node)) != NULL) {
|
||||
return;
|
||||
}
|
||||
map_set(map, hash_pointer(node), node);
|
||||
|
||||
|
||||
DeclInfo **found = map_get(&info->entities, hash_pointer(node));
|
||||
if (found == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeclInfo *decl = *found;
|
||||
gb_for_array(i, decl->deps.entries) {
|
||||
Entity *e = cast(Entity *)cast(uintptr)decl->deps.entries[i].key.key;
|
||||
add_dependency_to_map(map, info, e);
|
||||
}
|
||||
}
|
||||
|
||||
Map<Entity *> generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
|
||||
Map<Entity *> map = {}; // Key: Entity *
|
||||
map_init(&map, gb_heap_allocator());
|
||||
|
||||
add_dependency_to_map(&map, info, start);
|
||||
|
||||
gb_for_array(i, info->entities.entries) {
|
||||
auto *entry = &info->entities.entries[i];
|
||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
||||
if (e->scope->is_global) {
|
||||
// NOTE(bill): Require runtime stuff
|
||||
add_dependency_to_map(&map, info, e);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -853,7 +901,7 @@ void init_runtime_types(Checker *c) {
|
||||
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;
|
||||
auto *record = &base_type(e->type)->Record;
|
||||
|
||||
t_type_info_member = record->other_fields[0]->type;
|
||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||
@@ -899,7 +947,6 @@ void init_runtime_types(Checker *c) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void check_parsed_files(Checker *c) {
|
||||
|
||||
gbArray(AstNode *) import_decls;
|
||||
@@ -929,6 +976,7 @@ void check_parsed_files(Checker *c) {
|
||||
}
|
||||
|
||||
f->scope = scope;
|
||||
f->decl_info = make_declaration_info(c->allocator, f->scope);
|
||||
HashKey key = hash_string(f->tokenizer.fullpath);
|
||||
map_set(&file_scopes, key, scope);
|
||||
map_set(&c->info.files, key, f);
|
||||
@@ -963,10 +1011,11 @@ void check_parsed_files(Checker *c) {
|
||||
AstNode *value = cd->values[i];
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
Entity *e = make_entity_constant(c->allocator, file_scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
DeclInfo *di = make_declaration_info(c->allocator, file_scope);
|
||||
di->type_expr = cd->type;
|
||||
di->init_expr = value;
|
||||
add_file_entity(c, file_scope, name, e, di);
|
||||
add_entity_and_decl_info(c, name, e, di);
|
||||
}
|
||||
|
||||
isize lhs_count = gb_array_count(cd->names);
|
||||
@@ -999,6 +1048,7 @@ void check_parsed_files(Checker *c) {
|
||||
value = vd->values[i];
|
||||
}
|
||||
Entity *e = make_entity_variable(c->allocator, file_scope, name->Ident, NULL);
|
||||
e->identifier = name;
|
||||
entities[entity_index++] = e;
|
||||
|
||||
DeclInfo *d = di;
|
||||
@@ -1010,25 +1060,27 @@ void check_parsed_files(Checker *c) {
|
||||
d->var_decl_tags = vd->tags;
|
||||
}
|
||||
|
||||
add_file_entity(c, file_scope, name, e, d);
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(td, TypeDecl, decl);
|
||||
ast_node(n, Ident, td->name);
|
||||
Entity *e = make_entity_type_name(c->allocator, file_scope, *n, NULL);
|
||||
e->identifier = td->name;
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = td->type;
|
||||
add_file_entity(c, file_scope, td->name, e, d);
|
||||
add_entity_and_decl_info(c, td->name, e, d);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, decl);
|
||||
ast_node(n, Ident, pd->name);
|
||||
Token token = *n;
|
||||
Entity *e = make_entity_procedure(c->allocator, file_scope, token, NULL);
|
||||
e->identifier = pd->name;
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->proc_decl = decl;
|
||||
add_file_entity(c, file_scope, pd->name, e, d);
|
||||
add_entity_and_decl_info(c, pd->name, e, d);
|
||||
case_end;
|
||||
|
||||
default:
|
||||
@@ -1069,7 +1121,7 @@ void check_parsed_files(Checker *c) {
|
||||
warning(id->token, "Multiple #import of the same file within this scope");
|
||||
}
|
||||
|
||||
if (id->import_name.string == make_string(".")) {
|
||||
if (id->import_name.string == ".") {
|
||||
// NOTE(bill): Add imported entities to this file's scope
|
||||
gb_for_array(elem_index, scope->elements.entries) {
|
||||
Entity *e = scope->elements.entries[elem_index].value;
|
||||
@@ -1155,7 +1207,7 @@ void check_parsed_files(Checker *c) {
|
||||
check_global_entity(c, Entity_TypeName);
|
||||
|
||||
init_runtime_types(c);
|
||||
#if 1
|
||||
|
||||
check_global_entity(c, Entity_Constant);
|
||||
check_global_entity(c, Entity_Procedure);
|
||||
check_global_entity(c, Entity_Variable);
|
||||
@@ -1164,13 +1216,42 @@ void check_parsed_files(Checker *c) {
|
||||
gb_for_array(i, c->procs) {
|
||||
ProcedureInfo *pi = &c->procs[i];
|
||||
add_curr_ast_file(c, pi->file);
|
||||
|
||||
b32 bounds_check = (pi->tags & ProcTag_bounds_check) != 0;
|
||||
b32 no_bounds_check = (pi->tags & ProcTag_no_bounds_check) != 0;
|
||||
|
||||
auto prev_context = c->context;
|
||||
defer (c->context = prev_context);
|
||||
if (bounds_check) {
|
||||
c->context.stmt_state_flags |= StmtStateFlag_bounds_check;
|
||||
c->context.stmt_state_flags &= ~StmtStateFlag_no_bounds_check;
|
||||
} else if (no_bounds_check) {
|
||||
c->context.stmt_state_flags |= StmtStateFlag_no_bounds_check;
|
||||
c->context.stmt_state_flags &= ~StmtStateFlag_bounds_check;
|
||||
}
|
||||
|
||||
check_proc_body(c, pi->token, pi->decl, pi->type, pi->body);
|
||||
}
|
||||
|
||||
if (false) {
|
||||
gb_printf("Dependency graph:\n");
|
||||
gb_for_array(i, c->info.entities.entries) {
|
||||
auto *entry = &c->info.entities.entries[i];
|
||||
Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
|
||||
DeclInfo *d = entry->value;
|
||||
if (gb_array_count(d->deps.entries) > 0) {
|
||||
gb_printf("\t%.*s depends on\n", LIT(e->token.string));
|
||||
gb_for_array(j, d->deps.entries) {
|
||||
Entity *e = cast(Entity *)cast(uintptr)d->deps.entries[j].key.key;
|
||||
gb_printf("\t\t%.*s\n", LIT(e->token.string));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add untyped expression values
|
||||
gb_for_array(i, c->info.untyped.entries) {
|
||||
auto *entry = c->info.untyped.entries + i;
|
||||
auto *entry = &c->info.untyped.entries[i];
|
||||
HashKey key = entry->key;
|
||||
AstNode *expr = cast(AstNode *)cast(uintptr)key.key;
|
||||
ExpressionInfo *info = &entry->value;
|
||||
@@ -1181,24 +1262,6 @@ void check_parsed_files(Checker *c) {
|
||||
add_type_and_value(&c->info, expr, info->mode, info->type, info->value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
gb_for_array(i, c->parser->files) {
|
||||
AstFile *f = &c->parser->files[i];
|
||||
Scope *scope = f->scope;
|
||||
gb_for_array(j, scope->elements.entries) {
|
||||
Entity *e = scope->elements.entries[j].value;
|
||||
switch (e->kind) {
|
||||
case Entity_ImportName: {
|
||||
if (!e->ImportName.used) {
|
||||
warning(e->token, "Unused import name: %.*s", LIT(e->ImportName.name));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ struct Entity {
|
||||
Scope * scope;
|
||||
Token token;
|
||||
Type * type;
|
||||
AstNode * identifier; // Can be NULL
|
||||
|
||||
Entity * using_parent;
|
||||
AstNode * using_expr;
|
||||
|
||||
@@ -51,6 +53,7 @@ struct Entity {
|
||||
b8 is_field; // Is struct field
|
||||
} Variable;
|
||||
struct {
|
||||
b32 used;
|
||||
} TypeName;
|
||||
struct {
|
||||
b32 used;
|
||||
|
||||
+83
-81
@@ -18,8 +18,8 @@ void update_expr_type (Checker *c, AstNode *e, Type *type, b32 fina
|
||||
b32 check_is_assignable_to_using_subtype(Type *dst, Type *src) {
|
||||
Type *prev_src = src;
|
||||
// Type *prev_dst = dst;
|
||||
src = get_base_type(type_deref(src));
|
||||
// dst = get_base_type(type_deref(dst));
|
||||
src = base_type(type_deref(src));
|
||||
// dst = base_type(type_deref(dst));
|
||||
b32 src_is_ptr = src != prev_src;
|
||||
// b32 dst_is_ptr = dst != prev_dst;
|
||||
|
||||
@@ -62,8 +62,8 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
|
||||
return true;
|
||||
}
|
||||
|
||||
Type *src = get_base_type(s);
|
||||
Type *dst = get_base_type(type);
|
||||
Type *src = base_type(s);
|
||||
Type *dst = base_type(type);
|
||||
|
||||
|
||||
if (is_type_untyped(src)) {
|
||||
@@ -184,7 +184,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
||||
|
||||
|
||||
void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *> *entity_map) {
|
||||
t = get_base_type(type_deref(t));
|
||||
t = base_type(type_deref(t));
|
||||
gbString str = expr_to_string(node);
|
||||
defer (gb_string_free(str));
|
||||
|
||||
@@ -266,7 +266,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
AstNode *name = cd->names[i];
|
||||
Entity *e = entities[i];
|
||||
Token name_token = name->Ident;
|
||||
if (name_token.string == make_string("_")) {
|
||||
if (name_token.string == "_") {
|
||||
other_fields[other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
@@ -288,7 +288,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
add_entity(c, c->context.scope, td->name, e);
|
||||
check_type_decl(c, e, td->type, NULL, NULL);
|
||||
|
||||
if (name_token.string == make_string("_")) {
|
||||
if (name_token.string == "_") {
|
||||
other_fields[other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
@@ -299,7 +299,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
map_set(&entity_map, key, e);
|
||||
other_fields[other_field_index++] = e;
|
||||
}
|
||||
add_entity_use(&c->info, td->name, e);
|
||||
add_entity_use(c, td->name, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
type->Named.type_name = e;
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
|
||||
if (name_token.string == make_string("_")) {
|
||||
if (name_token.string == "_") {
|
||||
error(name_token, "`_` cannot be used a union subtype");
|
||||
continue;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
map_set(&entity_map, key, e);
|
||||
fields[field_index++] = e;
|
||||
}
|
||||
add_entity_use(&c->info, name, e);
|
||||
add_entity_use(c, name, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -365,7 +365,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
Token name_token = name->Ident;
|
||||
|
||||
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, vd->is_using, cast(i32)field_index);
|
||||
if (name_token.string == make_string("_")) {
|
||||
if (name_token.string == "_") {
|
||||
fields[field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
@@ -377,13 +377,13 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
fields[field_index++] = e;
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
add_entity_use(&c->info, name, e);
|
||||
add_entity_use(c, name, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vd->is_using) {
|
||||
Type *t = get_base_type(type_deref(type));
|
||||
Type *t = base_type(type_deref(type));
|
||||
if (!is_type_struct(t) && !is_type_raw_union(t)) {
|
||||
Token name_token = vd->names[0]->Ident;
|
||||
error(name_token, "`using` on a field `%.*s` must be a type", LIT(name_token.string));
|
||||
@@ -619,15 +619,15 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
ast_node(f, FieldValue, field);
|
||||
Token name_token = f->field->Ident;
|
||||
|
||||
if (name_token.string == make_string("count")) {
|
||||
if (name_token.string == "count") {
|
||||
error(name_token, "`count` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (name_token.string == make_string("min_value")) {
|
||||
} else if (name_token.string == "min_value") {
|
||||
error(name_token, "`min_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
} else if (name_token.string == make_string("max_value")) {
|
||||
} else if (name_token.string == "max_value") {
|
||||
error(name_token, "`max_value` is a reserved identifier for enumerations");
|
||||
fields[field_index++] = blank_entity;
|
||||
continue;
|
||||
@@ -672,7 +672,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
add_entity(c, c->context.scope, NULL, e);
|
||||
fields[field_index++] = e;
|
||||
}
|
||||
add_entity_use(&c->info, f->field, e);
|
||||
add_entity_use(c, f->field, e);
|
||||
}
|
||||
|
||||
gb_sort_array(fields, gb_array_count(et->fields), cmp_enum_order);
|
||||
@@ -802,7 +802,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
o->expr = n;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string);
|
||||
if (e == NULL) {
|
||||
if (n->Ident.string == make_string("_")) {
|
||||
if (n->Ident.string == "_") {
|
||||
error(n->Ident, "`_` cannot be used as a value type");
|
||||
} else {
|
||||
error(n->Ident, "Undeclared name: %.*s", LIT(n->Ident.string));
|
||||
@@ -814,7 +814,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
}
|
||||
return;
|
||||
}
|
||||
add_entity_use(&c->info, n, e);
|
||||
add_entity_use(c, n, e);
|
||||
|
||||
CycleChecker local_cycle_checker = {};
|
||||
if (cycle_checker == NULL) {
|
||||
@@ -835,19 +835,21 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Constant:
|
||||
add_declaration_dependency(c, e);
|
||||
if (type == t_invalid)
|
||||
if (type == t_invalid) {
|
||||
o->type = t_invalid;
|
||||
return;
|
||||
}
|
||||
o->value = e->Constant.value;
|
||||
GB_ASSERT(o->value.kind != ExactValue_Invalid);
|
||||
o->mode = Addressing_Constant;
|
||||
break;
|
||||
|
||||
case Entity_Variable:
|
||||
add_declaration_dependency(c, e);
|
||||
e->Variable.used = true;
|
||||
if (type == t_invalid)
|
||||
if (type == t_invalid) {
|
||||
o->type = t_invalid;
|
||||
return;
|
||||
}
|
||||
o->mode = Addressing_Variable;
|
||||
break;
|
||||
|
||||
@@ -872,7 +874,6 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
} break;
|
||||
|
||||
case Entity_Procedure:
|
||||
add_declaration_dependency(c, e);
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
@@ -996,7 +997,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
||||
|
||||
case_ast_node(vt, VectorType, e);
|
||||
Type *elem = check_type(c, vt->elem);
|
||||
Type *be = get_base_type(elem);
|
||||
Type *be = base_type(elem);
|
||||
i64 count = check_array_count(c, vt->count);
|
||||
if (!is_type_boolean(be) && !is_type_numeric(be)) {
|
||||
err_str = type_to_string(elem);
|
||||
@@ -1097,7 +1098,7 @@ end:
|
||||
|
||||
b32 check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = get_base_type(base_vector_type(get_base_type(o->type)));
|
||||
Type *type = base_type(base_vector_type(o->type));
|
||||
gbString str = NULL;
|
||||
defer (gb_string_free(str));
|
||||
switch (op.kind) {
|
||||
@@ -1132,7 +1133,7 @@ b32 check_unary_op(Checker *c, Operand *o, Token op) {
|
||||
|
||||
b32 check_binary_op(Checker *c, Operand *o, Token op) {
|
||||
// TODO(bill): Handle errors correctly
|
||||
Type *type = get_base_type(base_vector_type(o->type));
|
||||
Type *type = base_type(base_vector_type(o->type));
|
||||
switch (op.kind) {
|
||||
case Token_Add:
|
||||
case Token_Sub:
|
||||
@@ -1285,7 +1286,7 @@ b32 check_is_expr_vector_index(Checker *c, AstNode *expr) {
|
||||
ast_node(ie, IndexExpr, expr);
|
||||
Type *t = type_of_expr(&c->info, ie->expr);
|
||||
if (t != NULL) {
|
||||
return is_type_vector(get_base_type(t));
|
||||
return is_type_vector(base_type(t));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1313,7 +1314,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
|
||||
}
|
||||
|
||||
if (o->mode == Addressing_Constant) {
|
||||
Type *type = get_base_type(o->type);
|
||||
Type *type = base_type(o->type);
|
||||
GB_ASSERT(type->kind == Type_Basic);
|
||||
i32 precision = 0;
|
||||
if (is_type_unsigned(type))
|
||||
@@ -1344,13 +1345,13 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
switch (op.kind) {
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
defined = is_type_comparable(get_base_type(x->type));
|
||||
defined = is_type_comparable(base_type(x->type));
|
||||
break;
|
||||
case Token_Lt:
|
||||
case Token_Gt:
|
||||
case Token_LtEq:
|
||||
case Token_GtEq: {
|
||||
defined = is_type_ordered(get_base_type(x->type));
|
||||
defined = is_type_ordered(base_type(x->type));
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -1385,8 +1386,8 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
update_expr_type(c, y->expr, default_type(y->type), true);
|
||||
}
|
||||
|
||||
if (is_type_vector(get_base_type(y->type))) {
|
||||
x->type = make_type_vector(c->allocator, t_bool, get_base_type(y->type)->Vector.count);
|
||||
if (is_type_vector(base_type(y->type))) {
|
||||
x->type = make_type_vector(c->allocator, t_bool, base_type(y->type)->Vector.count);
|
||||
} else {
|
||||
x->type = t_untyped_bool;
|
||||
}
|
||||
@@ -1461,7 +1462,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
|
||||
x->value = exact_value_shift(be->op, x_val, make_exact_value_integer(amount));
|
||||
|
||||
if (is_type_typed(x->type)) {
|
||||
check_is_expressible(c, x, get_base_type(x->type));
|
||||
check_is_expressible(c, x, base_type(x->type));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1491,8 +1492,8 @@ b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
return true;
|
||||
|
||||
Type *x = operand->type;
|
||||
Type *xb = get_base_type(x);
|
||||
Type *yb = get_base_type(y);
|
||||
Type *xb = base_type(x);
|
||||
Type *yb = base_type(y);
|
||||
if (are_types_identical(xb, yb)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1561,7 +1562,7 @@ String check_down_cast_name(Type *dst_, Type *src_) {
|
||||
String result = {};
|
||||
Type *dst = type_deref(dst_);
|
||||
Type *src = type_deref(src_);
|
||||
Type *dst_s = get_base_type(dst);
|
||||
Type *dst_s = base_type(dst);
|
||||
GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s));
|
||||
for (isize i = 0; i < dst_s->Record.field_count; i++) {
|
||||
Entity *f = dst_s->Record.fields[i];
|
||||
@@ -1603,10 +1604,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
b32 is_const_expr = x->mode == Addressing_Constant;
|
||||
b32 can_convert = false;
|
||||
|
||||
Type *base_type = get_base_type(type);
|
||||
if (is_const_expr && is_type_constant_type(base_type)) {
|
||||
if (base_type->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, x->value, base_type, &x->value)) {
|
||||
Type *bt = base_type(type);
|
||||
if (is_const_expr && is_type_constant_type(bt)) {
|
||||
if (bt->kind == Type_Basic) {
|
||||
if (check_value_is_expressible(c, x->value, bt, &x->value)) {
|
||||
can_convert = true;
|
||||
}
|
||||
}
|
||||
@@ -1707,8 +1708,8 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
|
||||
Type *src = type_deref(x->type);
|
||||
Type *dst = type_deref(type);
|
||||
Type *bsrc = get_base_type(src);
|
||||
Type *bdst = get_base_type(dst);
|
||||
Type *bsrc = base_type(src);
|
||||
Type *bdst = base_type(dst);
|
||||
|
||||
if (!(is_type_struct(bsrc) || is_type_raw_union(bsrc))) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
@@ -1823,7 +1824,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
ExactValue a = x->value;
|
||||
ExactValue b = y->value;
|
||||
|
||||
Type *type = get_base_type(x->type);
|
||||
Type *type = base_type(x->type);
|
||||
GB_ASSERT(type->kind == Type_Basic);
|
||||
if (op.kind == Token_Quo && is_type_integer(type)) {
|
||||
op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers
|
||||
@@ -1869,7 +1870,7 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) {
|
||||
}
|
||||
|
||||
if (!final && is_type_untyped(type)) {
|
||||
found->type = get_base_type(type);
|
||||
found->type = base_type(type);
|
||||
map_set(&c->info.untyped, key, *found);
|
||||
} else {
|
||||
ExpressionInfo old = *found;
|
||||
@@ -1934,7 +1935,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
Type *t = get_enum_base_type(get_base_type(target_type));
|
||||
Type *t = get_enum_base_type(base_type(target_type));
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
@@ -2015,7 +2016,8 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
|
||||
return false;
|
||||
}
|
||||
|
||||
if (operand.mode == Addressing_Constant) {
|
||||
if (operand.mode == Addressing_Constant &&
|
||||
(c->context.stmt_state_flags & StmtStateFlag_bounds_check) != 0) {
|
||||
i64 i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i < 0) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
@@ -2031,7 +2033,7 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
|
||||
if (i >= max_count) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(ast_node_token(operand.expr),
|
||||
"Index `%s` is out of bounds range [0, %lld)", expr_str, max_count);
|
||||
"Index `%s` is out of bounds range 0..<%lld", expr_str, max_count);
|
||||
gb_string_free(expr_str);
|
||||
return false;
|
||||
}
|
||||
@@ -2062,7 +2064,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
if (op_expr->kind == AstNode_Ident) {
|
||||
String name = op_expr->Ident.string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
add_entity_use(&c->info, op_expr, e);
|
||||
add_entity_use(c, op_expr, e);
|
||||
if (e != NULL && e->kind == Entity_ImportName) {
|
||||
String sel_name = selector->Ident.string;
|
||||
check_op_expr = false;
|
||||
@@ -2091,7 +2093,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
// NOTE(bill): Not really an error so don't goto error
|
||||
}
|
||||
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
add_entity_use(c, selector, entity);
|
||||
}
|
||||
}
|
||||
if (check_op_expr) {
|
||||
@@ -2116,7 +2118,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
}
|
||||
|
||||
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
add_entity_use(c, selector, entity);
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
@@ -2186,7 +2188,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
Type *type = op.type;
|
||||
if (op.mode != Addressing_Type && type == NULL || type == t_invalid) {
|
||||
if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `new`");
|
||||
return false;
|
||||
}
|
||||
@@ -2198,7 +2200,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
Operand op = {};
|
||||
check_expr_or_type(c, &op, ce->args[0]);
|
||||
Type *type = op.type;
|
||||
if (op.mode != Addressing_Type && type == NULL || type == t_invalid) {
|
||||
if ((op.mode != Addressing_Type && type == NULL) || type == t_invalid) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `new_slice`");
|
||||
return false;
|
||||
}
|
||||
@@ -2297,7 +2299,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_offset_of: {
|
||||
// offset_val :: proc(Type, field) -> int
|
||||
Operand op = {};
|
||||
Type *type = get_base_type(check_type(c, ce->args[0]));
|
||||
Type *type = base_type(check_type(c, ce->args[0]));
|
||||
if (type != NULL || type == t_invalid) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`");
|
||||
return false;
|
||||
@@ -2345,8 +2347,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
return false;
|
||||
|
||||
Type *type = operand->type;
|
||||
if (get_base_type(type)->kind == Type_Pointer) {
|
||||
Type *p = get_base_type(type);
|
||||
if (base_type(type)->kind == Type_Pointer) {
|
||||
Type *p = base_type(type);
|
||||
if (is_type_struct(p)) {
|
||||
type = p->Pointer.elem;
|
||||
}
|
||||
@@ -2456,7 +2458,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
// copy :: proc(x, y: []Type) -> int
|
||||
Type *dest_type = NULL, *src_type = NULL;
|
||||
|
||||
Type *d = get_base_type(operand->type);
|
||||
Type *d = base_type(operand->type);
|
||||
if (d->kind == Type_Slice)
|
||||
dest_type = d->Slice.elem;
|
||||
|
||||
@@ -2464,7 +2466,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
check_expr(c, &op, ce->args[1]);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
Type *s = get_base_type(op.type);
|
||||
Type *s = base_type(op.type);
|
||||
if (s->kind == Type_Slice)
|
||||
src_type = s->Slice.elem;
|
||||
|
||||
@@ -2495,13 +2497,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_append: {
|
||||
// append :: proc(x : ^[]Type, y : Type) -> bool
|
||||
Type *x_type = NULL, *y_type = NULL;
|
||||
x_type = get_base_type(operand->type);
|
||||
x_type = base_type(operand->type);
|
||||
|
||||
Operand op = {};
|
||||
check_expr(c, &op, ce->args[1]);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
y_type = get_base_type(op.type);
|
||||
y_type = base_type(op.type);
|
||||
|
||||
if (!(is_type_pointer(x_type) && is_type_slice(x_type->Pointer.elem))) {
|
||||
error(ast_node_token(call), "First argument to `append` must be a pointer to a slice");
|
||||
@@ -2530,7 +2532,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
case BuiltinProc_swizzle: {
|
||||
// swizzle :: proc(v: {N}T, T...) -> {M}T
|
||||
Type *vector_type = get_base_type(operand->type);
|
||||
Type *vector_type = base_type(operand->type);
|
||||
if (!is_type_vector(vector_type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2549,7 +2551,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
check_expr(c, &op, arg);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
Type *arg_type = get_base_type(op.type);
|
||||
Type *arg_type = base_type(op.type);
|
||||
if (!is_type_integer(arg_type) || op.mode != Addressing_Constant) {
|
||||
error(ast_node_token(op.expr), "Indices to `swizzle` must be constant integers");
|
||||
return false;
|
||||
@@ -2581,7 +2583,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_ptr_offset: {
|
||||
// ptr_offset :: proc(ptr: ^T, offset: int) -> ^T
|
||||
// ^T cannot be rawptr
|
||||
Type *ptr_type = get_base_type(operand->type);
|
||||
Type *ptr_type = base_type(operand->type);
|
||||
if (!is_type_pointer(ptr_type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2602,7 +2604,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
check_expr(c, &op, offset);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
Type *offset_type = get_base_type(op.type);
|
||||
Type *offset_type = base_type(op.type);
|
||||
if (!is_type_integer(offset_type)) {
|
||||
error(ast_node_token(op.expr), "Pointer offsets for `ptr_offset` must be an integer");
|
||||
return false;
|
||||
@@ -2623,7 +2625,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_ptr_sub: {
|
||||
// ptr_sub :: proc(a, b: ^T) -> int
|
||||
// ^T cannot be rawptr
|
||||
Type *ptr_type = get_base_type(operand->type);
|
||||
Type *ptr_type = base_type(operand->type);
|
||||
if (!is_type_pointer(ptr_type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2652,7 +2654,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_base_type(op.type) == t_rawptr) {
|
||||
if (base_type(op.type) == t_rawptr) {
|
||||
error(ast_node_token(call),
|
||||
"`rawptr` cannot have pointer arithmetic");
|
||||
return false;
|
||||
@@ -2684,7 +2686,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
case BuiltinProc_slice_ptr: {
|
||||
// slice_ptr :: proc(a: ^T, len: int[, cap: int]) -> []T
|
||||
// ^T cannot be rawptr
|
||||
Type *ptr_type = get_base_type(operand->type);
|
||||
Type *ptr_type = base_type(operand->type);
|
||||
if (!is_type_pointer(ptr_type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2744,7 +2746,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
case BuiltinProc_min: {
|
||||
// min :: proc(a, b: comparable) -> comparable
|
||||
Type *type = get_base_type(operand->type);
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_comparable(type) || !is_type_numeric(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2804,7 +2806,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
case BuiltinProc_max: {
|
||||
// min :: proc(a, b: comparable) -> comparable
|
||||
Type *type = get_base_type(operand->type);
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_comparable(type) || !is_type_numeric(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2864,7 +2866,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
case BuiltinProc_abs: {
|
||||
// abs :: proc(n: numeric) -> numeric
|
||||
Type *type = get_base_type(operand->type);
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_numeric(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -2894,7 +2896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
} break;
|
||||
|
||||
case BuiltinProc_enum_to_string: {
|
||||
Type *type = get_base_type(operand->type);
|
||||
Type *type = base_type(operand->type);
|
||||
if (!is_type_enum(type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
@@ -3003,7 +3005,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
|
||||
if (variadic_expand) {
|
||||
check_assignment(c, operand, arg_type, make_string("argument"), true);
|
||||
} else {
|
||||
arg_type = get_base_type(arg_type)->Slice.elem;
|
||||
arg_type = base_type(arg_type)->Slice.elem;
|
||||
check_assignment(c, operand, arg_type, make_string("argument"), true);
|
||||
}
|
||||
} else {
|
||||
@@ -3033,7 +3035,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
|
||||
}
|
||||
Type *arg_type = sig_params[index]->type;
|
||||
if (end_variadic && is_type_slice(arg_type)) {
|
||||
arg_type = get_base_type(arg_type)->Slice.elem;
|
||||
arg_type = base_type(arg_type)->Slice.elem;
|
||||
}
|
||||
check_assignment(c, operand, arg_type, make_string("argument"), true);
|
||||
param_index++;
|
||||
@@ -3099,7 +3101,7 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
return builtin_procs[id].kind;
|
||||
}
|
||||
|
||||
Type *proc_type = get_base_type(operand->type);
|
||||
Type *proc_type = base_type(operand->type);
|
||||
if (proc_type == NULL || proc_type->kind != Type_Proc) {
|
||||
AstNode *e = operand->expr;
|
||||
gbString str = expr_to_string(e);
|
||||
@@ -3225,7 +3227,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
goto error;
|
||||
}
|
||||
|
||||
Type *t = get_base_type(type);
|
||||
Type *t = base_type(type);
|
||||
switch (t->kind) {
|
||||
case Type_Record: {
|
||||
if (!is_type_struct(t))
|
||||
@@ -3269,7 +3271,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
|
||||
Entity *field = t->Record.fields[sel.index[0]];
|
||||
add_entity_use(&c->info, kv->field, field);
|
||||
add_entity_use(c, kv->field, field);
|
||||
|
||||
if (fields_visited[sel.index[0]]) {
|
||||
error(ast_node_token(elem),
|
||||
@@ -3425,7 +3427,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
b32 valid = false;
|
||||
i64 max_count = -1;
|
||||
Type *t = get_base_type(o->type);
|
||||
Type *t = base_type(o->type);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (is_type_string(t)) {
|
||||
@@ -3463,7 +3465,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
break;
|
||||
|
||||
case Type_Pointer: {
|
||||
Type *bt = get_base_type(t->Pointer.elem);
|
||||
Type *bt = base_type(t->Pointer.elem);
|
||||
if (bt->kind == Type_Array) {
|
||||
valid = true;
|
||||
max_count = bt->Array.count;
|
||||
@@ -3501,7 +3503,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
b32 valid = false;
|
||||
i64 max_count = -1;
|
||||
Type *t = get_base_type(o->type);
|
||||
Type *t = base_type(o->type);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (is_type_string(t)) {
|
||||
@@ -3533,7 +3535,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
break;
|
||||
|
||||
case Type_Pointer: {
|
||||
Type *bt = get_base_type(t->Pointer.elem);
|
||||
Type *bt = base_type(t->Pointer.elem);
|
||||
if (bt->kind == Type_Array) {
|
||||
valid = true;
|
||||
max_count = bt->Array.count;
|
||||
@@ -3591,7 +3593,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
if (o->mode == Addressing_Invalid) {
|
||||
goto error;
|
||||
} else {
|
||||
Type *t = get_base_type(o->type);
|
||||
Type *t = base_type(o->type);
|
||||
if (t->kind == Type_Pointer) {
|
||||
o->mode = Addressing_Variable;
|
||||
o->type = t->Pointer.elem;
|
||||
|
||||
+63
-43
@@ -17,7 +17,10 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
Entity *e;
|
||||
DeclInfo *d;
|
||||
};
|
||||
gbArray(Delay) delayed; gb_array_init(delayed, gb_heap_allocator());
|
||||
gbArray(Delay) delayed_const; gb_array_init(delayed_const, gb_heap_allocator());
|
||||
gbArray(Delay) delayed_type; gb_array_init(delayed_type, gb_heap_allocator());
|
||||
defer (gb_array_free(delayed_const));
|
||||
defer (gb_array_free(delayed_type));
|
||||
|
||||
gb_for_array(i, stmts) {
|
||||
AstNode *node = stmts[i];
|
||||
@@ -29,6 +32,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
add_entity(c, e->scope, name, e);
|
||||
|
||||
DeclInfo *di = make_declaration_info(c->allocator, e->scope);
|
||||
@@ -36,7 +40,7 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
di->init_expr = value;
|
||||
|
||||
Delay delay = {e, di};
|
||||
gb_array_append(delayed, delay);
|
||||
gb_array_append(delayed_const, delay);
|
||||
}
|
||||
|
||||
isize lhs_count = gb_array_count(cd->names);
|
||||
@@ -51,27 +55,24 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
|
||||
case_ast_node(td, TypeDecl, node);
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, td->name->Ident, NULL);
|
||||
e->identifier = td->name;
|
||||
add_entity(c, c->context.scope, td->name, e);
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = td->type;
|
||||
|
||||
Delay delay = {e, d};
|
||||
gb_array_append(delayed, delay);
|
||||
gb_array_append(delayed_type, delay);
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
auto check_scope_entity = [](Checker *c, gbArray(Delay) delayed, EntityKind kind) {
|
||||
gb_for_array(i, delayed) {
|
||||
auto delay = delayed[i];
|
||||
if (delay.e->kind == kind) {
|
||||
check_entity_decl(c, delay.e, delay.d, NULL);
|
||||
}
|
||||
}
|
||||
};
|
||||
check_scope_entity(c, delayed, Entity_TypeName);
|
||||
check_scope_entity(c, delayed, Entity_Constant);
|
||||
gb_for_array(i, delayed_type) {
|
||||
check_entity_decl(c, delayed_type[i].e, delayed_type[i].d, NULL);
|
||||
}
|
||||
gb_for_array(i, delayed_const) {
|
||||
check_entity_decl(c, delayed_const[i].e, delayed_const[i].d, NULL);
|
||||
}
|
||||
|
||||
b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
|
||||
u32 f = flags & (~Stmt_FallthroughAllowed);
|
||||
@@ -227,7 +228,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
|
||||
// NOTE(bill): Ignore assignments to `_`
|
||||
if (node->kind == AstNode_Ident &&
|
||||
node->Ident.string == make_string("_")) {
|
||||
node->Ident.string == "_") {
|
||||
add_entity_definition(&c->info, node, NULL);
|
||||
check_assignment(c, op_a, NULL, make_string("assignment to `_` identifier"));
|
||||
if (op_a->mode == Addressing_Invalid)
|
||||
@@ -301,8 +302,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
|
||||
|
||||
if (e->type == NULL)
|
||||
if (e->type == NULL) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -321,8 +323,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
|
||||
check_assignment(c, operand, e->type, context_name);
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return e->type;
|
||||
}
|
||||
@@ -448,9 +451,9 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle
|
||||
gb_array_free(local_cycle_checker.path);
|
||||
});
|
||||
|
||||
Type *base_type = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
|
||||
named->Named.base = base_type;
|
||||
named->Named.base = get_base_type(named->Named.base);
|
||||
Type *bt = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
|
||||
named->Named.base = bt;
|
||||
named->Named.base = base_type(named->Named.base);
|
||||
if (named->Named.base == t_invalid) {
|
||||
gb_printf("check_type_decl: %s\n", type_to_string(named));
|
||||
}
|
||||
@@ -474,7 +477,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
if (!e->Variable.anonymous)
|
||||
continue;
|
||||
String name = e->token.string;
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
@@ -524,8 +527,8 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < a->param_count; i++) {
|
||||
Type *x = get_base_type(a->params->Tuple.variables[i]->type);
|
||||
Type *y = get_base_type(b->params->Tuple.variables[i]->type);
|
||||
Type *x = base_type(a->params->Tuple.variables[i]->type);
|
||||
Type *y = base_type(b->params->Tuple.variables[i]->type);
|
||||
if (is_type_pointer(x) && is_type_pointer(y)) {
|
||||
continue;
|
||||
}
|
||||
@@ -535,8 +538,8 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < a->result_count; i++) {
|
||||
Type *x = get_base_type(a->results->Tuple.variables[i]->type);
|
||||
Type *y = get_base_type(b->results->Tuple.variables[i]->type);
|
||||
Type *x = base_type(a->results->Tuple.variables[i]->type);
|
||||
Type *y = base_type(b->results->Tuple.variables[i]->type);
|
||||
if (is_type_pointer(x) && is_type_pointer(y)) {
|
||||
continue;
|
||||
}
|
||||
@@ -559,15 +562,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
defer (check_close_scope(c));
|
||||
check_procedure_type(c, proc_type, pd->type);
|
||||
|
||||
|
||||
b32 is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||
b32 is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||
b32 is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||
b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||
|
||||
b32 is_foreign = (pd->tags & ProcTag_foreign) != 0;
|
||||
b32 is_link_name = (pd->tags & ProcTag_link_name) != 0;
|
||||
b32 is_inline = (pd->tags & ProcTag_inline) != 0;
|
||||
b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0;
|
||||
|
||||
if ((d->scope->is_file || d->scope->is_global) &&
|
||||
e->token.string == make_string("main")) {
|
||||
e->token.string == "main") {
|
||||
if (proc_type != NULL) {
|
||||
auto *pt = &proc_type->Proc;
|
||||
if (pt->param_count != 0 ||
|
||||
@@ -595,7 +596,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
d->scope = c->context.scope;
|
||||
|
||||
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
|
||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body);
|
||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body, pd->tags);
|
||||
}
|
||||
|
||||
if (is_foreign) {
|
||||
@@ -610,8 +611,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
if (found) {
|
||||
Entity *f = *found;
|
||||
TokenPos pos = f->token.pos;
|
||||
Type *this_type = get_base_type(e->type);
|
||||
Type *other_type = get_base_type(f->type);
|
||||
Type *this_type = base_type(e->type);
|
||||
Type *other_type = base_type(f->type);
|
||||
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||
error(ast_node_token(d->proc_decl),
|
||||
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
||||
@@ -639,7 +640,6 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
map_set(fp, key, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) {
|
||||
@@ -674,7 +674,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
|
||||
AstNodeArray inits;
|
||||
gb_array_init(inits, c->allocator);
|
||||
gb_array_init_reserve(inits, c->allocator, 1);
|
||||
gb_array_append(inits, init_expr);
|
||||
check_init_variables(c, entities, entity_count, inits, make_string("variable declaration"));
|
||||
}
|
||||
@@ -701,9 +701,10 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc
|
||||
check_proc_decl(c, e, d);
|
||||
return;
|
||||
}
|
||||
Scope *prev = c->context.scope;
|
||||
auto prev = c->context;
|
||||
c->context.scope = d->scope;
|
||||
defer (c->context.scope = prev);
|
||||
c->context.decl = d;
|
||||
defer (c->context = prev);
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Constant:
|
||||
@@ -790,6 +791,24 @@ void check_var_decl_node(Checker *c, AstNode *node) {
|
||||
|
||||
|
||||
void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
u32 prev_stmt_state_flags = c->context.stmt_state_flags;
|
||||
defer (c->context.stmt_state_flags = prev_stmt_state_flags);
|
||||
|
||||
if (node->stmt_state_flags != 0) {
|
||||
u32 in = node->stmt_state_flags;
|
||||
u32 out = c->context.stmt_state_flags;
|
||||
defer (c->context.stmt_state_flags = out);
|
||||
|
||||
if (in & StmtStateFlag_bounds_check) {
|
||||
out |= StmtStateFlag_bounds_check;
|
||||
out &= ~StmtStateFlag_no_bounds_check;
|
||||
} else if (in & StmtStateFlag_no_bounds_check) {
|
||||
out |= StmtStateFlag_no_bounds_check;
|
||||
out &= ~StmtStateFlag_bounds_check;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
|
||||
switch (node->kind) {
|
||||
case_ast_node(_, EmptyStmt, node); case_end;
|
||||
@@ -1180,7 +1199,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
"Expected a pointer to a union for this type match expression, got `%s`", str);
|
||||
break;
|
||||
}
|
||||
Type *base_union = get_base_type(type_deref(x.type));
|
||||
Type *base_union = base_type(type_deref(x.type));
|
||||
|
||||
|
||||
// NOTE(bill): Check for multiple defaults
|
||||
@@ -1274,7 +1293,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tag_ptr_type);
|
||||
tag_var->Variable.used = true;
|
||||
add_entity(c, c->context.scope, ms->var, tag_var);
|
||||
add_entity_use(&c->info, ms->var, tag_var);
|
||||
add_entity_use(c, ms->var, tag_var);
|
||||
}
|
||||
check_stmt_list(c, cc->stmts, mod_flags);
|
||||
check_close_scope(c);
|
||||
@@ -1342,7 +1361,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = get_base_type(e->type);
|
||||
Type *t = base_type(e->type);
|
||||
if (is_type_struct(t) || is_type_enum(t)) {
|
||||
for (isize i = 0; i < t->Record.other_field_count; i++) {
|
||||
Entity *f = t->Record.other_fields[i];
|
||||
@@ -1404,7 +1423,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
break;
|
||||
|
||||
case Entity_Variable: {
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
@@ -1444,7 +1463,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
ast_node(i, Ident, item);
|
||||
String name = i->string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
GB_ASSERT(found != NULL);
|
||||
@@ -1511,6 +1530,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
|
||||
// e.g. using
|
||||
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);
|
||||
e->identifier = pd->name;
|
||||
add_entity(c, c->context.scope, pd->name, e);
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
|
||||
+100
-79
@@ -92,8 +92,8 @@ enum TypeRecordKind {
|
||||
};
|
||||
|
||||
struct Type {
|
||||
u32 flags; // See parser.cpp `enum TypeFlag`
|
||||
TypeKind kind;
|
||||
u32 flags; // See parser.cpp `enum TypeFlag`
|
||||
union {
|
||||
BasicType Basic;
|
||||
struct {
|
||||
@@ -157,7 +157,7 @@ struct Type {
|
||||
|
||||
gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator());
|
||||
|
||||
Type *get_base_type(Type *t) {
|
||||
Type *base_type(Type *t) {
|
||||
for (;;) {
|
||||
if (t == NULL || t->kind != Type_Named) {
|
||||
break;
|
||||
@@ -259,7 +259,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun
|
||||
}
|
||||
GB_ASSERT(params != NULL && params->kind == Type_Tuple);
|
||||
Entity *e = params->Tuple.variables[param_count-1];
|
||||
if (get_base_type(e->type)->kind != Type_Slice) {
|
||||
if (base_type(e->type)->kind != Type_Slice) {
|
||||
// NOTE(bill): For custom calling convention
|
||||
GB_PANIC("variadic parameter must be of type slice");
|
||||
}
|
||||
@@ -277,7 +277,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun
|
||||
|
||||
Type *type_deref(Type *t) {
|
||||
if (t != NULL) {
|
||||
Type *bt = get_base_type(t);
|
||||
Type *bt = base_type(t);
|
||||
if (bt == NULL)
|
||||
return NULL;
|
||||
if (bt != NULL && bt->kind == Type_Pointer)
|
||||
@@ -289,34 +289,34 @@ Type *type_deref(Type *t) {
|
||||
|
||||
#define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1}
|
||||
gb_global Type basic_types[] = {
|
||||
{0, Type_Basic, {Basic_Invalid, 0, STR_LIT("invalid type")}},
|
||||
{0, Type_Basic, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}},
|
||||
{0, Type_Basic, {Basic_i8, BasicFlag_Integer, STR_LIT("i8")}},
|
||||
{0, Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}},
|
||||
{0, Type_Basic, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}},
|
||||
{0, Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}},
|
||||
{0, Type_Basic, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}},
|
||||
{0, Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}},
|
||||
{0, Type_Basic, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}},
|
||||
{0, Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}},
|
||||
{0, Type_Basic, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}},
|
||||
{0, Type_Basic, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}},
|
||||
{0, Type_Basic, {Basic_int, BasicFlag_Integer, STR_LIT("int")}},
|
||||
{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")}},
|
||||
{0, Type_Basic, {Basic_UntypedPointer, BasicFlag_Pointer | BasicFlag_Untyped, STR_LIT("untyped pointer")}},
|
||||
{0, Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}},
|
||||
{0, Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}},
|
||||
{Type_Basic, 0, {Basic_Invalid, 0, STR_LIT("invalid type")}},
|
||||
{Type_Basic, 0, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}},
|
||||
{Type_Basic, 0, {Basic_i8, BasicFlag_Integer, STR_LIT("i8")}},
|
||||
{Type_Basic, 0, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}},
|
||||
{Type_Basic, 0, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}},
|
||||
{Type_Basic, 0, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}},
|
||||
{Type_Basic, 0, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}},
|
||||
{Type_Basic, 0, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}},
|
||||
{Type_Basic, 0, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}},
|
||||
{Type_Basic, 0, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}},
|
||||
{Type_Basic, 0, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}},
|
||||
{Type_Basic, 0, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}},
|
||||
{Type_Basic, 0, {Basic_int, BasicFlag_Integer, STR_LIT("int")}},
|
||||
{Type_Basic, 0, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}},
|
||||
{Type_Basic, 0, {Basic_rawptr, BasicFlag_Pointer, STR_LIT("rawptr")}},
|
||||
{Type_Basic, 0, {Basic_string, BasicFlag_String, STR_LIT("string")}},
|
||||
{Type_Basic, 0, {Basic_any, 0, STR_LIT("any")}},
|
||||
{Type_Basic, 0, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}},
|
||||
{Type_Basic, 0, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}},
|
||||
{Type_Basic, 0, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}},
|
||||
{Type_Basic, 0, {Basic_UntypedPointer, BasicFlag_Pointer | BasicFlag_Untyped, STR_LIT("untyped pointer")}},
|
||||
{Type_Basic, 0, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}},
|
||||
{Type_Basic, 0, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}},
|
||||
};
|
||||
|
||||
gb_global Type basic_type_aliases[] = {
|
||||
{0, Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}},
|
||||
{0, Type_Basic, {Basic_rune, BasicFlag_Integer, STR_LIT("rune")}},
|
||||
{Type_Basic, 0, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}},
|
||||
{Type_Basic, 0, {Basic_rune, BasicFlag_Integer, STR_LIT("rune")}},
|
||||
};
|
||||
|
||||
gb_global Type *t_invalid = &basic_types[Basic_Invalid];
|
||||
@@ -342,8 +342,8 @@ gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
|
||||
gb_global Type *t_untyped_pointer = &basic_types[Basic_UntypedPointer];
|
||||
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
|
||||
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_byte = &basic_type_aliases[0];
|
||||
gb_global Type *t_rune = &basic_type_aliases[1];
|
||||
|
||||
|
||||
gb_global Type *t_type_info = NULL;
|
||||
@@ -377,140 +377,161 @@ gb_global Type *t_context_ptr = NULL;
|
||||
|
||||
|
||||
b32 is_type_named(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
if (t->kind == Type_Basic) {
|
||||
return true;
|
||||
}
|
||||
return t->kind == Type_Named;
|
||||
}
|
||||
b32 is_type_boolean(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Boolean) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_integer(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Integer) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_unsigned(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_numeric(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Numeric) != 0;
|
||||
if (t->kind == Type_Vector)
|
||||
}
|
||||
if (t->kind == Type_Vector) {
|
||||
return is_type_numeric(t->Vector.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_string(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_String) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_typed(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Untyped) == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
b32 is_type_untyped(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Untyped) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_ordered(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Ordered) != 0;
|
||||
if (t->kind == Type_Pointer)
|
||||
}
|
||||
if (t->kind == Type_Pointer) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_constant_type(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
||||
}
|
||||
if (t->kind == Type_Record) {
|
||||
return t->Record.kind == TypeRecord_Enum;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_float(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Float) != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_pointer(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Basic)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & BasicFlag_Pointer) != 0;
|
||||
}
|
||||
return t->kind == Type_Pointer;
|
||||
}
|
||||
|
||||
b32 is_type_int_or_uint(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.kind == Basic_int) || (t->Basic.kind == Basic_uint);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_rawptr(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_rawptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_u8(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_u8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_slice(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Slice;
|
||||
}
|
||||
b32 is_type_u8_slice(Type *t) {
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Slice)
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Slice) {
|
||||
return is_type_u8(t->Slice.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
b32 is_type_vector(Type *t) {
|
||||
return t->kind == Type_Vector;
|
||||
}
|
||||
b32 is_type_proc(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return t->kind == Type_Proc;
|
||||
}
|
||||
Type *base_vector_type(Type *t) {
|
||||
if (is_type_vector(t)) {
|
||||
return t->Vector.elem;
|
||||
return base_type(t)->Vector.elem;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
b32 is_type_enum(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum);
|
||||
}
|
||||
b32 is_type_struct(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct);
|
||||
}
|
||||
b32 is_type_union(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Union);
|
||||
}
|
||||
b32 is_type_raw_union(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
|
||||
}
|
||||
|
||||
Type *get_enum_base_type(Type *t) {
|
||||
Type *bt = get_base_type(t);
|
||||
Type *bt = base_type(t);
|
||||
if (is_type_enum(bt)) {
|
||||
return bt->Record.enum_base;
|
||||
}
|
||||
@@ -518,14 +539,14 @@ Type *get_enum_base_type(Type *t) {
|
||||
}
|
||||
|
||||
b32 is_type_any(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_any);
|
||||
}
|
||||
|
||||
|
||||
|
||||
b32 is_type_comparable(Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return true;
|
||||
@@ -722,13 +743,13 @@ gb_global Entity *entity__slice_capacity = NULL;
|
||||
Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
|
||||
if (field_name == make_string("_")) {
|
||||
if (field_name == "_") {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
type = get_base_type(type);
|
||||
type = base_type(type);
|
||||
|
||||
if (type->kind == Type_Basic) {
|
||||
switch (type->Basic.kind) {
|
||||
@@ -850,13 +871,13 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
}
|
||||
|
||||
if (is_type_enum(type)) {
|
||||
if (field_name == make_string("count")) {
|
||||
if (field_name == "count") {
|
||||
sel.entity = type->Record.enum_count;
|
||||
return sel;
|
||||
} else if (field_name == make_string("min_value")) {
|
||||
} else if (field_name == "min_value") {
|
||||
sel.entity = type->Record.min_value;
|
||||
return sel;
|
||||
} else if (field_name == make_string("max_value")) {
|
||||
} else if (field_name == "max_value") {
|
||||
sel.entity = type->Record.max_value;
|
||||
return sel;
|
||||
}
|
||||
@@ -907,7 +928,7 @@ i64 align_formula(i64 size, i64 align) {
|
||||
}
|
||||
|
||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Array:
|
||||
@@ -996,7 +1017,7 @@ b32 type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
}
|
||||
|
||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic: {
|
||||
@@ -1107,7 +1128,7 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
|
||||
i64 offset = 0;
|
||||
for (isize i = 0; i < gb_array_count(sel.index); i++) {
|
||||
isize index = sel.index[i];
|
||||
t = get_base_type(t);
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
|
||||
Reference in New Issue
Block a user