mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-05 10:14:05 +00:00
Move cycle checking to much earlier on in the semantic stage
This commit is contained in:
@@ -227,6 +227,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
error(decl->attributes[0], "Attributes are not allowed on type declarations");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_distinct = is_type_distinct(type_expr);
|
||||
AstNode *te = remove_type_alias_clutter(type_expr);
|
||||
e->type = t_invalid;
|
||||
@@ -238,7 +240,10 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
}
|
||||
e->type = named;
|
||||
|
||||
Type *bt = check_type(c, te, named);
|
||||
check_type_path_push(c, e);
|
||||
Type *bt = check_type_expr(c, te, named);
|
||||
check_type_path_pop(c);
|
||||
|
||||
named->Named.base = base_type(bt);
|
||||
if (!is_distinct) {
|
||||
e->type = bt;
|
||||
@@ -985,7 +990,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ void check_multi_expr (Checker *c, Operand *operand, AstNode *
|
||||
void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = nullptr);
|
||||
ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
|
||||
void check_expr_with_type_hint (Checker *c, Operand *o, AstNode *e, Type *t);
|
||||
Type * check_type (Checker *c, AstNode *expression, Type *named_type = nullptr);
|
||||
Type * check_type (Checker *c, AstNode *expression);
|
||||
Type * check_type_expr (Checker *c, AstNode *expression, Type *named_type);
|
||||
Type * make_optional_ok_type (Type *value);
|
||||
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def);
|
||||
Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint);
|
||||
@@ -334,7 +335,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ
|
||||
d->proc_lit = proc_lit;
|
||||
|
||||
|
||||
Entity *entity = make_entity_procedure(c->allocator, nullptr, token, final_proc_type, tags);
|
||||
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
||||
entity->identifier = ident;
|
||||
|
||||
add_entity_and_decl_info(c, ident, entity, d);
|
||||
@@ -903,6 +904,27 @@ bool is_polymorphic_type_assignable(Checker *c, Type *poly, Type *source, bool c
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_cycle(Checker *c, Entity *curr, bool report) {
|
||||
if (curr->state != EntityState_InProgress) {
|
||||
return false;
|
||||
}
|
||||
for_array(i, *c->context.type_path) {
|
||||
Entity *prev = (*c->context.type_path)[i];
|
||||
if (prev == curr) {
|
||||
if (report) {
|
||||
error(curr->token, "Illegal declaration cycle of `%.*s`", LIT(curr->token.string));
|
||||
for (isize j = i; j < c->context.type_path->count; j++) {
|
||||
Entity *curr = (*c->context.type_path)[j];
|
||||
error(curr->token, "\t%.*s refers to", LIT(curr->token.string));
|
||||
}
|
||||
error(curr->token, "\t%.*s", LIT(curr->token.string));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
|
||||
GB_ASSERT(n->kind == AstNode_Ident);
|
||||
@@ -1036,6 +1058,9 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
|
||||
|
||||
case Entity_TypeName:
|
||||
o->mode = Addressing_Type;
|
||||
if (check_cycle(c, e, true)) {
|
||||
type = t_invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case Entity_ImportName:
|
||||
@@ -3152,8 +3177,8 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
|
||||
Type *proc_type_params = alloc_type_tuple(c->allocator);
|
||||
proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
|
||||
proc_type_params->Tuple.variable_count = 2;
|
||||
proc_type_params->Tuple.variables[0] = make_entity_param(c->allocator, nullptr, blank_token, operand->type, false, false);
|
||||
proc_type_params->Tuple.variables[1] = make_entity_param(c->allocator, nullptr, blank_token, slice_elem, false, false);
|
||||
proc_type_params->Tuple.variables[0] = alloc_entity_param(c->allocator, nullptr, blank_token, operand->type, false, false);
|
||||
proc_type_params->Tuple.variables[1] = alloc_entity_param(c->allocator, nullptr, blank_token, slice_elem, false, false);
|
||||
Type *proc_type = alloc_type_proc(nullptr, proc_type_params, 2, nullptr, false, true, ProcCC_Odin);
|
||||
|
||||
check_call_arguments(c, &prev_operand, proc_type, call);
|
||||
|
||||
@@ -431,7 +431,7 @@ void check_label(Checker *c, AstNode *label) {
|
||||
}
|
||||
}
|
||||
|
||||
Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident.token, t_invalid, label);
|
||||
Entity *e = alloc_entity_label(c->context.scope, l->name->Ident.token, t_invalid, label);
|
||||
add_entity(c, c->context.scope, l->name, e);
|
||||
e->parent_proc_decl = c->context.curr_proc_decl;
|
||||
|
||||
@@ -507,7 +507,7 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo
|
||||
for_array(i, found->elements.entries) {
|
||||
Entity *f = found->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->using_expr = expr;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
@@ -1000,7 +1000,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) {
|
||||
|
||||
check_open_scope(c, stmt);
|
||||
{
|
||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident.token, case_type, false, EntityState_Resolved);
|
||||
Entity *tag_var = alloc_entity_variable(c->context.scope, lhs->Ident.token, case_type, false, EntityState_Resolved);
|
||||
tag_var->flags |= EntityFlag_Used;
|
||||
tag_var->flags |= EntityFlag_Value;
|
||||
add_entity(c, c->context.scope, lhs, tag_var);
|
||||
@@ -1467,7 +1467,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
if (found == nullptr) {
|
||||
bool is_immutable = true;
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, type, is_immutable, EntityState_Resolved);
|
||||
entity = alloc_entity_variable(c->context.scope, token, type, is_immutable, EntityState_Resolved);
|
||||
add_entity_definition(&c->info, name, entity);
|
||||
} else {
|
||||
TokenPos pos = found->token.pos;
|
||||
@@ -1482,7 +1482,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
|
||||
if (entity == nullptr) {
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||
entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name));
|
||||
}
|
||||
|
||||
entities[entity_count++] = entity;
|
||||
@@ -1700,7 +1700,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->using_expr = expr;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
@@ -1797,7 +1797,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
new_name_count += 1;
|
||||
}
|
||||
if (found == nullptr) {
|
||||
entity = make_entity_variable(c->allocator, c->context.scope, token, nullptr, false);
|
||||
entity = alloc_entity_variable(c->context.scope, token, nullptr, false);
|
||||
entity->identifier = name;
|
||||
|
||||
AstNode *fl = c->context.foreign_context.curr_library;
|
||||
@@ -1816,7 +1816,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
}
|
||||
if (entity == nullptr) {
|
||||
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
|
||||
entity = alloc_entity_dummy_variable(c->global_scope, ast_node_token(name));
|
||||
}
|
||||
entity->parent_proc_decl = c->context.curr_proc_decl;
|
||||
entities[entity_count++] = entity;
|
||||
@@ -1828,7 +1828,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
Type *init_type = nullptr;
|
||||
if (vd->type != nullptr) {
|
||||
init_type = check_type(c, vd->type, nullptr);
|
||||
init_type = check_type(c, vd->type);
|
||||
if (init_type == nullptr) {
|
||||
init_type = t_invalid;
|
||||
} else if (is_type_polymorphic(base_type(init_type))) {
|
||||
@@ -1938,7 +1938,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
|
||||
@@ -111,7 +111,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
|
||||
gb_printf_err("Element\n");
|
||||
}
|
||||
|
||||
type = check_type(c, type_expr);
|
||||
type = check_type_expr(c, type_expr, nullptr);
|
||||
|
||||
if (default_value != nullptr) {
|
||||
Operand o = {};
|
||||
@@ -179,7 +179,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
|
||||
Token name_token = name->Ident.token;
|
||||
|
||||
Entity *field = nullptr;
|
||||
field = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, field_src_index);
|
||||
field = alloc_entity_field(c->context.scope, name_token, type, is_using, field_src_index);
|
||||
field->Variable.default_value = value;
|
||||
field->Variable.default_is_nil = default_is_nil;
|
||||
|
||||
@@ -211,8 +211,7 @@ void check_struct_fields(Checker *c, AstNode *node, Array<Entity *> *fields, Arr
|
||||
|
||||
|
||||
Entity *make_names_field_for_struct(Checker *c, Scope *scope) {
|
||||
Entity *e = make_entity_field(c->allocator, scope,
|
||||
make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||
Entity *e = alloc_entity_field(scope, make_token_ident(str_lit("names")), t_string_slice, false, 0);
|
||||
e->Variable.is_immutable = true;
|
||||
e->flags |= EntityFlag_TypeField;
|
||||
return e;
|
||||
@@ -311,7 +310,7 @@ void add_polymorphic_struct_entity(Checker *c, AstNode *node, Type *named_type,
|
||||
node->kind = AstNode_Ident;
|
||||
node->Ident.token = token;
|
||||
|
||||
e = make_entity_type_name(a, s, token, named_type);
|
||||
e = alloc_entity_type_name(s, token, named_type);
|
||||
e->state = EntityState_Resolved;
|
||||
add_entity_use(c, node, e);
|
||||
}
|
||||
@@ -454,18 +453,18 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
|
||||
is_polymorphic = true;
|
||||
can_check_fields = false;
|
||||
}
|
||||
e = make_entity_type_name(c->allocator, scope, token, operand.type);
|
||||
e = alloc_entity_type_name(scope, token, operand.type);
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
GB_ASSERT(operand.mode == Addressing_Constant);
|
||||
e = make_entity_constant(c->allocator, scope, token, operand.type, operand.value);
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
}
|
||||
} else {
|
||||
if (is_type_param) {
|
||||
e = make_entity_type_name(c->allocator, scope, token, type);
|
||||
e = alloc_entity_type_name(scope, token, type);
|
||||
e->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
e = make_entity_constant(c->allocator, scope, token, type, empty_exact_value);
|
||||
e = alloc_entity_constant(scope, token, type, empty_exact_value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +550,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
AstNode *node = ut->variants[i];
|
||||
Type *t = check_type(c, node);
|
||||
Type *t = check_type_expr(c, node, nullptr);
|
||||
if (t != nullptr && t != t_invalid) {
|
||||
bool ok = true;
|
||||
t = default_type(t);
|
||||
@@ -697,7 +696,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
max_value = iota;
|
||||
}
|
||||
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident.token, constant_type, iota);
|
||||
Entity *e = alloc_entity_constant(c->context.scope, ident->Ident.token, constant_type, iota);
|
||||
e->identifier = ident;
|
||||
e->flags |= EntityFlag_Visited;
|
||||
e->state = EntityState_Resolved;
|
||||
@@ -732,12 +731,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
}
|
||||
}
|
||||
|
||||
enum_type->Enum.count = make_entity_constant(c->allocator, c->context.scope,
|
||||
make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
|
||||
enum_type->Enum.min_value = make_entity_constant(c->allocator, c->context.scope,
|
||||
make_token_ident(str_lit("min_value")), constant_type, min_value);
|
||||
enum_type->Enum.max_value = make_entity_constant(c->allocator, c->context.scope,
|
||||
make_token_ident(str_lit("max_value")), constant_type, max_value);
|
||||
Scope *s = c->context.scope;
|
||||
enum_type->Enum.count = alloc_entity_constant(s, make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
|
||||
enum_type->Enum.min_value = alloc_entity_constant(s, make_token_ident(str_lit("min_value")), constant_type, min_value);
|
||||
enum_type->Enum.max_value = alloc_entity_constant(s, make_token_ident(str_lit("max_value")), constant_type, max_value);
|
||||
|
||||
enum_type->Enum.names = make_names_field_for_struct(c, c->context.scope);
|
||||
}
|
||||
@@ -789,7 +786,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, AstNode *node) {
|
||||
u32 bits = cast(u32)bits_;
|
||||
|
||||
Type *value_type = alloc_type_bit_field_value(bits);
|
||||
Entity *e = make_entity_variable(c->allocator, bit_field_type->BitField.scope, ident->Ident.token, value_type, false);
|
||||
Entity *e = alloc_entity_variable(bit_field_type->BitField.scope, ident->Ident.token, value_type, false);
|
||||
e->identifier = ident;
|
||||
e->flags |= EntityFlag_BitFieldValue;
|
||||
|
||||
@@ -1184,7 +1181,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
type = t_invalid;
|
||||
}
|
||||
}
|
||||
param = make_entity_type_name(c->allocator, scope, name->Ident.token, type, EntityState_Resolved);
|
||||
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
|
||||
param->TypeName.is_type_alias = true;
|
||||
} else {
|
||||
if (operands != nullptr && variables.count < operands->count) {
|
||||
@@ -1207,7 +1204,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
}
|
||||
}
|
||||
|
||||
param = make_entity_param(c->allocator, scope, name->Ident.token, type, is_using, is_in);
|
||||
param = alloc_entity_param(scope, name->Ident.token, type, is_using, is_in);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
param->Variable.default_is_location = default_is_location;
|
||||
@@ -1336,7 +1333,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
if (field->names.count == 0) {
|
||||
Token token = ast_node_token(field->type);
|
||||
token.string = str_lit("");
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
Entity *param = alloc_entity_param(scope, token, type, false, false);
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
array_add(&variables, param);
|
||||
@@ -1359,7 +1356,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
|
||||
error(name, "Result value cannot be a blank identifer `_`");
|
||||
}
|
||||
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
|
||||
Entity *param = alloc_entity_param(scope, token, type, false, false);
|
||||
param->flags |= EntityFlag_Result;
|
||||
param->Variable.default_value = value;
|
||||
param->Variable.default_is_nil = default_is_nil;
|
||||
@@ -1542,7 +1539,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
|
||||
if (new_type != original_type) {
|
||||
Type *tuple = alloc_type_tuple();
|
||||
auto variables = array_make<Entity *>(a, 0, 1);
|
||||
array_add(&variables, make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false));
|
||||
array_add(&variables, alloc_entity_param(original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false));
|
||||
tuple->Tuple.variables = variables;
|
||||
new_type = tuple;
|
||||
}
|
||||
@@ -1732,8 +1729,8 @@ Type *make_optional_ok_type(Type *value) {
|
||||
bool typed = true;
|
||||
Type *t = alloc_type_tuple();
|
||||
array_init(&t->Tuple.variables, a, 0, 2);
|
||||
array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, value, false, 0));
|
||||
array_add (&t->Tuple.variables, make_entity_field(a, nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1));
|
||||
array_add (&t->Tuple.variables, alloc_entity_field(nullptr, blank_token, value, false, 0));
|
||||
array_add (&t->Tuple.variables, alloc_entity_field(nullptr, blank_token, typed ? t_bool : t_untyped_bool, false, 1));
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -1759,9 +1756,9 @@ void init_map_entry_type(Type *type) {
|
||||
Scope *s = create_scope(universal_scope, a);
|
||||
|
||||
auto fields = array_make<Entity *>(a, 0, 3);
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved));
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved));
|
||||
|
||||
|
||||
entry_type->Struct.fields = fields;
|
||||
@@ -1799,8 +1796,8 @@ void init_map_internal_types(Type *type) {
|
||||
|
||||
|
||||
auto fields = array_make<Entity *>(a, 0, 2);
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("hashes")), hashes_type, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, make_entity_field(a, s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hashes")), hashes_type, false, 0, EntityState_Resolved));
|
||||
array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved));
|
||||
|
||||
generated_struct_type->Struct.fields = fields;
|
||||
|
||||
@@ -1837,6 +1834,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) {
|
||||
// error(node, "'map' types are not yet implemented");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) {
|
||||
GB_ASSERT_NOT_NULL(type);
|
||||
if (e == nullptr) {
|
||||
@@ -1846,7 +1845,6 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
|
||||
switch (e->kind) {
|
||||
case_ast_node(i, Ident, e);
|
||||
|
||||
Operand o = {};
|
||||
Entity *entity = check_ident(c, &o, e, named_type, nullptr, false);
|
||||
|
||||
@@ -1867,9 +1865,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
}
|
||||
}
|
||||
|
||||
if (c->context.type_level == 0 && entity->state == EntityState_InProgress) {
|
||||
error(e, "Illegal declaration cycle of `%.*s`", LIT(entity->token.string));
|
||||
}
|
||||
// if (c->context.type_level == 0 && entity->state == EntityState_InProgress) {
|
||||
// error(entity->token, "Illegal declaration cycle of `%.*s`", LIT(entity->token.string));
|
||||
// for_array(j, *c->context.type_path) {
|
||||
// Entity *k = (*c->context.type_path)[j];
|
||||
// error(k->token, "\t%.*s refers to", LIT(k->token.string));
|
||||
// }
|
||||
// error(entity->token, "\t%.*s", LIT(entity->token.string));
|
||||
// *type = t_invalid;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1927,7 +1931,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
GB_ASSERT(is_scope_an_ancestor(ps, s) >= 0);
|
||||
entity_scope = ps;
|
||||
}
|
||||
Entity *e = make_entity_type_name(c->allocator, entity_scope, token, t);
|
||||
Entity *e = alloc_entity_type_name(entity_scope, token, t);
|
||||
e->TypeName.is_type_alias = true;
|
||||
e->state = EntityState_Resolved;
|
||||
add_entity(c, ps, ident, e);
|
||||
@@ -1968,7 +1972,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
case_end;
|
||||
|
||||
case_ast_node(pe, ParenExpr, e);
|
||||
*type = check_type(c, pe->expr, named_type);
|
||||
*type = check_type_expr(c, pe->expr, named_type);
|
||||
set_base_type(named_type, *type);
|
||||
return true;
|
||||
case_end;
|
||||
@@ -2000,7 +2004,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
error(at->count, "... can only be used in conjuction with compound literals");
|
||||
count = 0;
|
||||
}
|
||||
Type *elem = check_type(c, at->elem, nullptr);
|
||||
Type *elem = check_type_expr(c, at->elem, nullptr);
|
||||
*type = alloc_type_array(elem, count, generic_type);
|
||||
} else {
|
||||
Type *elem = check_type(c, at->elem);
|
||||
@@ -2117,9 +2121,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *check_type(Checker *c, AstNode *e) {
|
||||
auto prev_context = c->context; defer (c->context = prev_context);
|
||||
c->context.type_path = new_checker_type_path();
|
||||
defer (destroy_checker_type_path(c->context.type_path));
|
||||
|
||||
return check_type_expr(c, e, nullptr);
|
||||
}
|
||||
|
||||
Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
Type *check_type_expr(Checker *c, AstNode *e, Type *named_type) {
|
||||
Type *type = nullptr;
|
||||
bool ok = check_type_internal(c, e, &type, named_type);
|
||||
|
||||
|
||||
104
src/checker.cpp
104
src/checker.cpp
@@ -507,20 +507,20 @@ Entity *add_global_entity(Entity *entity) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(a, Entity_Constant, nullptr, make_token_ident(name), type);
|
||||
void add_global_constant(String name, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(Entity_Constant, nullptr, make_token_ident(name), type);
|
||||
entity->Constant.value = value;
|
||||
add_global_entity(entity);
|
||||
}
|
||||
|
||||
|
||||
void add_global_string_constant(gbAllocator a, String name, String value) {
|
||||
add_global_constant(a, name, t_untyped_string, exact_value_string(value));
|
||||
void add_global_string_constant(String name, String value) {
|
||||
add_global_constant(name, t_untyped_string, exact_value_string(value));
|
||||
}
|
||||
|
||||
|
||||
void add_global_type_entity(gbAllocator a, String name, Type *type) {
|
||||
add_global_entity(make_entity_type_name(a, nullptr, make_token_ident(name), type));
|
||||
void add_global_type_entity(String name, Type *type) {
|
||||
add_global_entity(alloc_entity_type_name(nullptr, make_token_ident(name), type));
|
||||
}
|
||||
|
||||
|
||||
@@ -533,27 +533,27 @@ void init_universal_scope(void) {
|
||||
|
||||
// Types
|
||||
for (isize i = 0; i < gb_count_of(basic_types); i++) {
|
||||
add_global_type_entity(a, basic_types[i].Basic.name, &basic_types[i]);
|
||||
add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]);
|
||||
}
|
||||
add_global_type_entity(a, str_lit("byte"), &basic_types[Basic_u8]);
|
||||
add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
|
||||
|
||||
// Constants
|
||||
add_global_constant(a, str_lit("true"), t_untyped_bool, exact_value_bool(true));
|
||||
add_global_constant(a, str_lit("false"), t_untyped_bool, exact_value_bool(false));
|
||||
add_global_constant(str_lit("true"), t_untyped_bool, exact_value_bool(true));
|
||||
add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false));
|
||||
|
||||
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
|
||||
add_global_entity(make_entity_library_name(a, universal_scope,
|
||||
make_token_ident(str_lit("__llvm_core")), t_invalid,
|
||||
str_lit(""), str_lit("__llvm_core")));
|
||||
add_global_entity(alloc_entity_nil(str_lit("nil"), t_untyped_nil));
|
||||
add_global_entity(alloc_entity_library_name(universal_scope,
|
||||
make_token_ident(str_lit("__llvm_core")), t_invalid,
|
||||
str_lit(""), str_lit("__llvm_core")));
|
||||
|
||||
// TODO(bill): Set through flags in the compiler
|
||||
add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS);
|
||||
add_global_string_constant(a, str_lit("ODIN_ARCH"), bc->ODIN_ARCH);
|
||||
add_global_string_constant(a, str_lit("ODIN_ENDIAN"), bc->ODIN_ENDIAN);
|
||||
add_global_string_constant(a, str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR);
|
||||
add_global_string_constant(a, str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
|
||||
add_global_string_constant(a, str_lit("ODIN_ROOT"), bc->ODIN_ROOT);
|
||||
add_global_constant(a, str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG));
|
||||
add_global_string_constant(str_lit("ODIN_OS"), bc->ODIN_OS);
|
||||
add_global_string_constant(str_lit("ODIN_ARCH"), bc->ODIN_ARCH);
|
||||
add_global_string_constant(str_lit("ODIN_ENDIAN"), bc->ODIN_ENDIAN);
|
||||
add_global_string_constant(str_lit("ODIN_VENDOR"), bc->ODIN_VENDOR);
|
||||
add_global_string_constant(str_lit("ODIN_VERSION"), bc->ODIN_VERSION);
|
||||
add_global_string_constant(str_lit("ODIN_ROOT"), bc->ODIN_ROOT);
|
||||
add_global_constant(str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG));
|
||||
|
||||
|
||||
// Builtin Procedures
|
||||
@@ -561,7 +561,7 @@ void init_universal_scope(void) {
|
||||
BuiltinProcId id = cast(BuiltinProcId)i;
|
||||
String name = builtin_procs[i].name;
|
||||
if (name != "") {
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, nullptr, make_token_ident(name), t_invalid);
|
||||
Entity *entity = alloc_entity(Entity_Builtin, nullptr, make_token_ident(name), t_invalid);
|
||||
entity->Builtin.id = id;
|
||||
add_global_entity(entity);
|
||||
}
|
||||
@@ -639,12 +639,17 @@ void init_checker(Checker *c, Parser *parser) {
|
||||
c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
|
||||
|
||||
c->global_scope = create_scope(universal_scope, c->allocator);
|
||||
c->context.scope = c->global_scope;
|
||||
|
||||
map_init(&c->file_scopes, heap_allocator());
|
||||
ptr_set_init(&c->checked_files, heap_allocator());
|
||||
|
||||
array_init(&c->file_order, heap_allocator(), 0, c->parser->files.count);
|
||||
|
||||
// Init context
|
||||
c->context.scope = c->global_scope;
|
||||
|
||||
c->context.type_path = new_checker_type_path();
|
||||
c->context.type_level = 0;
|
||||
}
|
||||
|
||||
void destroy_checker(Checker *c) {
|
||||
@@ -660,6 +665,8 @@ void destroy_checker(Checker *c) {
|
||||
map_destroy(&c->file_scopes);
|
||||
ptr_set_destroy(&c->checked_files);
|
||||
array_free(&c->file_order);
|
||||
|
||||
destroy_checker_type_path(c->context.type_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -1312,6 +1319,31 @@ Type *find_core_type(Checker *c, String name) {
|
||||
return e->type;
|
||||
}
|
||||
|
||||
CheckerTypePath *new_checker_type_path() {
|
||||
gbAllocator a = heap_allocator();
|
||||
auto *tp = gb_alloc_item(a, CheckerTypePath);
|
||||
array_init(tp, a, 0, 16);
|
||||
return tp;
|
||||
}
|
||||
|
||||
void destroy_checker_type_path(CheckerTypePath *tp) {
|
||||
array_free(tp);
|
||||
gb_free(heap_allocator(), tp);
|
||||
}
|
||||
|
||||
|
||||
void check_type_path_push(Checker *c, Entity *e) {
|
||||
GB_ASSERT(c->context.type_path != nullptr);
|
||||
GB_ASSERT(e != nullptr);
|
||||
array_add(c->context.type_path, e);
|
||||
}
|
||||
Entity *check_type_path_pop(Checker *c) {
|
||||
GB_ASSERT(c->context.type_path != nullptr);
|
||||
return array_pop(c->context.type_path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type);
|
||||
|
||||
@@ -1424,9 +1456,9 @@ void init_preload(Checker *c) {
|
||||
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
|
||||
Scope *preload_scope = type_info_entity->scope;
|
||||
|
||||
Entity *e = make_entity_import_name(c->allocator, preload_scope, make_token_ident(_global), t_invalid,
|
||||
str_lit(""), _global,
|
||||
preload_scope);
|
||||
Entity *e = alloc_entity_import_name(preload_scope, make_token_ident(_global), t_invalid,
|
||||
str_lit(""), _global,
|
||||
preload_scope);
|
||||
|
||||
add_entity(c, universal_scope, nullptr, e);
|
||||
}
|
||||
@@ -1745,7 +1777,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
|
||||
error(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
|
||||
continue;
|
||||
}
|
||||
Entity *e = make_entity_variable(c->allocator, c->context.scope, name->Ident.token, nullptr, false);
|
||||
Entity *e = alloc_entity_variable(c->context.scope, name->Ident.token, nullptr, false);
|
||||
e->identifier = name;
|
||||
|
||||
if (vd->is_using) {
|
||||
@@ -1808,7 +1840,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
|
||||
|
||||
if (is_ast_node_type(init) ||
|
||||
(vd->type != nullptr && vd->type->kind == AstNode_TypeType)) {
|
||||
e = make_entity_type_name(c->allocator, d->scope, token, nullptr);
|
||||
e = alloc_entity_type_name(d->scope, token, nullptr);
|
||||
if (vd->type != nullptr) {
|
||||
error(name, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
@@ -1820,7 +1852,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
|
||||
continue;
|
||||
}
|
||||
ast_node(pl, ProcLit, init);
|
||||
e = make_entity_procedure(c->allocator, d->scope, token, nullptr, pl->tags);
|
||||
e = alloc_entity_procedure(d->scope, token, nullptr, pl->tags);
|
||||
if (fl != nullptr) {
|
||||
GB_ASSERT(fl->kind == AstNode_Ident);
|
||||
e->Procedure.foreign_library_ident = fl;
|
||||
@@ -1846,13 +1878,13 @@ void check_collect_value_decl(Checker *c, AstNode *decl) {
|
||||
d->type_expr = pl->type;
|
||||
} else if (init->kind == AstNode_ProcGroup) {
|
||||
ast_node(pg, ProcGroup, init);
|
||||
e = make_entity_proc_group(c->allocator, d->scope, token, nullptr);
|
||||
e = alloc_entity_proc_group(d->scope, token, nullptr);
|
||||
if (fl != nullptr) {
|
||||
error(name, "Procedure groups are not allowed within a foreign block");
|
||||
}
|
||||
d->init_expr = init;
|
||||
} else {
|
||||
e = make_entity_constant(c->allocator, d->scope, token, nullptr, empty_exact_value);
|
||||
e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value);
|
||||
d->type_expr = vd->type;
|
||||
d->init_expr = init;
|
||||
}
|
||||
@@ -2340,9 +2372,9 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
|
||||
} else {
|
||||
GB_ASSERT(id->import_name.pos.line != 0);
|
||||
id->import_name.string = import_name;
|
||||
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
Entity *e = alloc_entity_import_name(parent_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
|
||||
add_entity(c, parent_scope, nullptr, e);
|
||||
}
|
||||
@@ -2524,8 +2556,8 @@ void check_add_foreign_import_decl(Checker *c, AstNode *decl) {
|
||||
|
||||
GB_ASSERT(fl->library_name.pos.line != 0);
|
||||
fl->library_name.string = library_name;
|
||||
Entity *e = make_entity_library_name(c->allocator, parent_scope, fl->library_name, t_invalid,
|
||||
fl->fullpath, library_name);
|
||||
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
|
||||
fl->fullpath, library_name);
|
||||
add_entity(c, parent_scope, nullptr, e);
|
||||
}
|
||||
|
||||
|
||||
@@ -262,19 +262,23 @@ struct ForeignContext {
|
||||
bool in_export;
|
||||
};
|
||||
|
||||
typedef Array<Entity *> CheckerTypePath;
|
||||
|
||||
struct CheckerContext {
|
||||
Scope * file_scope;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
u32 stmt_state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
isize type_level; // TODO(bill): Actually handle correctly
|
||||
String proc_name;
|
||||
Type * type_hint;
|
||||
DeclInfo * curr_proc_decl;
|
||||
Type * curr_proc_sig;
|
||||
ForeignContext foreign_context;
|
||||
|
||||
CheckerTypePath *type_path;
|
||||
isize type_level; // TODO(bill): Actually handle correctly
|
||||
|
||||
bool collect_delayed_decls;
|
||||
bool allow_polymorphic_types;
|
||||
bool no_polymorphic_errors;
|
||||
@@ -382,7 +386,6 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes);
|
||||
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(Checker *c, AstNode *decl);
|
||||
|
||||
|
||||
struct AttributeContext {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
@@ -401,3 +404,9 @@ AttributeContext make_attribute_context(String link_prefix) {
|
||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
||||
|
||||
void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
|
||||
CheckerTypePath *new_checker_type_path();
|
||||
void destroy_checker_type_path(CheckerTypePath *tp);
|
||||
|
||||
void check_type_path_push(Checker *c, Entity *e);
|
||||
Entity *check_type_path_pop (Checker *c);
|
||||
|
||||
@@ -177,7 +177,8 @@ bool is_entity_exported(Entity *e) {
|
||||
|
||||
gb_global u64 global_entity_id = 0;
|
||||
|
||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
gbAllocator a = heap_allocator();
|
||||
Entity *entity = gb_alloc_item(a, Entity);
|
||||
entity->kind = kind;
|
||||
entity->state = EntityState_Unresolved;
|
||||
@@ -188,17 +189,17 @@ Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *type, bool is_immutable, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(a, Entity_Variable, scope, token, type);
|
||||
Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_immutable, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(Entity_Variable, scope, token, type);
|
||||
entity->Variable.is_immutable = is_immutable;
|
||||
entity->state = state;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) {
|
||||
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) {
|
||||
GB_ASSERT(parent != nullptr);
|
||||
token.pos = parent->token.pos;
|
||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
entity->parent_proc_decl = parent->parent_proc_decl;
|
||||
entity->flags |= EntityFlag_Using;
|
||||
@@ -208,21 +209,21 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type);
|
||||
Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(Entity_Constant, scope, token, type);
|
||||
entity->Constant.value = value;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(a, Entity_TypeName, scope, token, type);
|
||||
Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(Entity_TypeName, scope, token, type);
|
||||
entity->state = state;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
|
||||
Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
|
||||
bool is_immutable = false;
|
||||
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
|
||||
Entity *entity = alloc_entity_variable(scope, token, type, is_immutable);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
entity->flags |= EntityFlag_Param;
|
||||
entity->state = EntityState_Resolved;
|
||||
@@ -232,8 +233,8 @@ Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
|
||||
Entity *entity = make_entity_constant(a, scope, token, type, value);
|
||||
Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
|
||||
Entity *entity = alloc_entity_constant(scope, token, type, value);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
if (poly_const) entity->flags |= EntityFlag_PolyConst;
|
||||
entity->flags |= EntityFlag_Param;
|
||||
@@ -241,8 +242,8 @@ Entity *make_entity_const_param(gbAllocator a, Scope *scope, Token token, Type *
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||
Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity_variable(scope, token, type, false);
|
||||
entity->Variable.field_src_index = field_src_index;
|
||||
entity->Variable.field_index = field_src_index;
|
||||
if (is_using) entity->flags |= EntityFlag_Using;
|
||||
@@ -251,8 +252,8 @@ Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_array_elem(gbAllocator a, Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type, false);
|
||||
Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_src_index) {
|
||||
Entity *entity = alloc_entity_variable(scope, token, type, false);
|
||||
entity->Variable.field_src_index = field_src_index;
|
||||
entity->Variable.field_index = field_src_index;
|
||||
entity->flags |= EntityFlag_Field;
|
||||
@@ -261,34 +262,34 @@ Entity *make_entity_array_elem(gbAllocator a, Scope *scope, Token token, Type *t
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_procedure(gbAllocator a, Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
Entity *entity = alloc_entity(a, Entity_Procedure, scope, token, signature_type);
|
||||
Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
|
||||
entity->Procedure.tags = tags;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_proc_group(gbAllocator a, Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = alloc_entity(a, Entity_ProcGroup, scope, token, type);
|
||||
Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type, i32 id) {
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, scope, token, type);
|
||||
Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) {
|
||||
Entity *entity = alloc_entity(Entity_Builtin, scope, token, type);
|
||||
entity->Builtin.id = id;
|
||||
entity->state = EntityState_Resolved;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
|
||||
Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
|
||||
Entity *alloc_entity_alias(Scope *scope, Token token, Type *type, Entity *base) {
|
||||
Entity *entity = alloc_entity(Entity_Alias, scope, token, type);
|
||||
entity->Alias.base = base;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
String path, String name, Scope *import_scope) {
|
||||
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
|
||||
Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||
String path, String name, Scope *import_scope) {
|
||||
Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
|
||||
entity->ImportName.path = path;
|
||||
entity->ImportName.name = name;
|
||||
entity->ImportName.scope = import_scope;
|
||||
@@ -296,9 +297,9 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
String path, String name) {
|
||||
Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
|
||||
Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
|
||||
String path, String name) {
|
||||
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
||||
entity->LibraryName.path = path;
|
||||
entity->LibraryName.name = name;
|
||||
entity->state = EntityState_Resolved; // TODO(bill): Is this correct?
|
||||
@@ -309,21 +310,20 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
|
||||
|
||||
|
||||
|
||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, nullptr, make_token_ident(name), type);
|
||||
Entity *alloc_entity_nil(String name, Type *type) {
|
||||
Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
AstNode *node) {
|
||||
Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
|
||||
Entity *alloc_entity_label(Scope *scope, Token token, Type *type, AstNode *node) {
|
||||
Entity *entity = alloc_entity(Entity_Label, scope, token, type);
|
||||
entity->Label.node = node;
|
||||
entity->state = EntityState_Resolved;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
|
||||
Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
|
||||
token.string = str_lit("_");
|
||||
return make_entity_variable(a, scope, token, nullptr, false);
|
||||
return alloc_entity_variable(scope, token, nullptr, false);
|
||||
}
|
||||
|
||||
|
||||
74
src/ir.cpp
74
src/ir.cpp
@@ -1206,10 +1206,7 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi
|
||||
|
||||
String s = make_string_c(text);
|
||||
|
||||
Entity *e = make_entity_variable(a, nullptr,
|
||||
make_token_ident(s),
|
||||
alloc_type_array(elem_type, count),
|
||||
false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(s), alloc_type_array(elem_type, count), false);
|
||||
irValue *value = ir_value_global(a, e, nullptr);
|
||||
value->Global.is_private = true;
|
||||
ir_module_add_value(m, e, value);
|
||||
@@ -1308,7 +1305,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
|
||||
|
||||
String name = make_string(str, len-1);
|
||||
|
||||
Entity *e = make_entity_constant(a, nullptr, make_token_ident(name), t, value);
|
||||
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
|
||||
irValue *g = ir_value_global(a, e, backing_array);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -1335,7 +1332,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
|
||||
token.string = name;
|
||||
Type *type = alloc_type_array(t_u8, string.len+1);
|
||||
ExactValue ev = exact_value_string(string);
|
||||
Entity *entity = make_entity_constant(a, nullptr, token, type, ev);
|
||||
Entity *entity = alloc_entity_constant(nullptr, token, type, ev);
|
||||
irValue *g = ir_value_global(a, entity, ir_add_module_constant(m, type, ev));
|
||||
g->Global.is_private = true;
|
||||
g->Global.is_unnamed_addr = true;
|
||||
@@ -1429,10 +1426,7 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type, bool zero_initial
|
||||
if (proc->curr_block) {
|
||||
scope = proc->curr_block->scope;
|
||||
}
|
||||
Entity *e = make_entity_variable(proc->module->allocator,
|
||||
scope,
|
||||
empty_token,
|
||||
type, false);
|
||||
Entity *e = alloc_entity_variable(scope, empty_token, type, false);
|
||||
return ir_add_local(proc, e, nullptr, zero_initialized);
|
||||
}
|
||||
|
||||
@@ -1450,11 +1444,7 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) {
|
||||
String name = make_string(str, len-1);
|
||||
|
||||
Scope *scope = nullptr;
|
||||
Entity *e = make_entity_variable(a,
|
||||
scope,
|
||||
make_token_ident(name),
|
||||
type, false);
|
||||
|
||||
Entity *e = alloc_entity_variable(scope, make_token_ident(name), type, false);
|
||||
irValue *g = ir_value_global(a, e, value);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -7389,7 +7379,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
|
||||
if (proc->type->Proc.return_by_pointer) {
|
||||
// NOTE(bill): this must be the first parameter stored
|
||||
Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results));
|
||||
Entity *e = make_entity_param(a, nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
|
||||
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false);
|
||||
e->flags |= EntityFlag_Sret | EntityFlag_NoAlias;
|
||||
|
||||
irValue *param = ir_value_param(a, proc, e, ptr_type);
|
||||
@@ -7472,7 +7462,7 @@ void ir_begin_procedure_body(irProcedure *proc) {
|
||||
|
||||
|
||||
if (proc->type->Proc.calling_convention == ProcCC_Odin) {
|
||||
Entity *e = make_entity_param(a, nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
|
||||
Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false);
|
||||
e->flags |= EntityFlag_NoAlias;
|
||||
irValue *param = ir_value_param(a, proc, e, e->type);
|
||||
ir_module_add_value(proc->module, e, param);
|
||||
@@ -7633,7 +7623,7 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
isize max_type_info_count = m->info->type_info_types.count;
|
||||
|
||||
String name = str_lit(IR_TYPE_INFO_DATA_NAME);
|
||||
Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name), alloc_type_array(t_type_info, max_type_info_count), false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), alloc_type_array(t_type_info, max_type_info_count), false);
|
||||
irValue *g = ir_value_global(m->allocator, e, nullptr);
|
||||
g->Global.is_private = true;
|
||||
ir_module_add_value(m, e, g);
|
||||
@@ -7664,8 +7654,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
|
||||
{
|
||||
String name = str_lit(IR_TYPE_INFO_TYPES_NAME);
|
||||
Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_type_info_ptr, count), false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_type_info_ptr, count), false);
|
||||
irValue *g = ir_value_global(m->allocator, e, nullptr);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -7673,8 +7663,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
}
|
||||
{
|
||||
String name = str_lit(IR_TYPE_INFO_NAMES_NAME);
|
||||
Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_string, count), false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_string, count), false);
|
||||
irValue *g = ir_value_global(m->allocator, e, nullptr);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -7682,8 +7672,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
}
|
||||
{
|
||||
String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME);
|
||||
Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_uintptr, count), false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_uintptr, count), false);
|
||||
irValue *g = ir_value_global(m->allocator, e, nullptr);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -7692,8 +7682,8 @@ void ir_init_module(irModule *m, Checker *c) {
|
||||
|
||||
{
|
||||
String name = str_lit(IR_TYPE_INFO_USINGS_NAME);
|
||||
Entity *e = make_entity_variable(m->allocator, nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_bool, count), false);
|
||||
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
|
||||
alloc_type_array(t_bool, count), false);
|
||||
irValue *g = ir_value_global(m->allocator, e, nullptr);
|
||||
ir_module_add_value(m, e, g);
|
||||
map_set(&m->members, hash_string(name), g);
|
||||
@@ -8487,12 +8477,12 @@ void ir_gen_tree(irGen *s) {
|
||||
array_init(&proc_params->Tuple.variables, a, 3);
|
||||
array_init(&proc_results->Tuple.variables, a, 1);
|
||||
|
||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
|
||||
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false, false);
|
||||
proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false, false);
|
||||
proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, make_token_ident(str_lit("reason")), t_i32, false, false);
|
||||
proc_params->Tuple.variables[2] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false, false);
|
||||
|
||||
|
||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
||||
proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false, false);
|
||||
|
||||
|
||||
Type *proc_type = alloc_type_proc(proc_scope,
|
||||
@@ -8507,7 +8497,7 @@ void ir_gen_tree(irGen *s) {
|
||||
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
||||
|
||||
AstNode *body = gb_alloc_item(a, AstNode);
|
||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||
Entity *e = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
|
||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||
|
||||
map_set(&m->values, hash_entity(e), p);
|
||||
@@ -8566,11 +8556,11 @@ void ir_gen_tree(irGen *s) {
|
||||
array_init(&proc_results->Tuple.variables, a, 1);
|
||||
|
||||
Type *cstring_ptr = alloc_type_pointer(t_cstring);
|
||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
|
||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, make_token_ident(str_lit("argv")), cstring_ptr, false, false);
|
||||
proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, make_token_ident(str_lit("argc")), t_i32, false, false);
|
||||
proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, make_token_ident(str_lit("argv")), cstring_ptr, false, false);
|
||||
|
||||
|
||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false, false);
|
||||
proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false, false);
|
||||
|
||||
|
||||
Type *proc_type = alloc_type_proc(proc_scope,
|
||||
@@ -8585,7 +8575,7 @@ void ir_gen_tree(irGen *s) {
|
||||
proc_type->Proc.abi_compat_result_type = proc_results->Tuple.variables[0]->type;
|
||||
|
||||
AstNode *body = gb_alloc_item(a, AstNode);
|
||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||
Entity *e = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
|
||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||
|
||||
map_set(&m->values, hash_entity(e), p);
|
||||
@@ -8636,12 +8626,12 @@ void ir_gen_tree(irGen *s) {
|
||||
proc_results->Tuple.variables = gb_alloc_array(a, Entity *, 1);
|
||||
proc_results->Tuple.variable_count = 1;
|
||||
|
||||
proc_params->Tuple.variables[0] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
||||
proc_params->Tuple.variables[1] = make_entity_param(a, proc_scope, blank_token, t_rawptr, false);
|
||||
proc_params->Tuple.variables[2] = make_entity_param(a, proc_scope, blank_token, t_u8_ptr, false);
|
||||
proc_params->Tuple.variables[3] = make_entity_param(a, proc_scope, blank_token, t_i32, false);
|
||||
proc_params->Tuple.variables[0] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false);
|
||||
proc_params->Tuple.variables[1] = alloc_entity_param(proc_scope, blank_token, t_rawptr, false);
|
||||
proc_params->Tuple.variables[2] = alloc_entity_param(proc_scope, blank_token, t_u8_ptr, false);
|
||||
proc_params->Tuple.variables[3] = alloc_entity_param(proc_scope, blank_token, t_i32, false);
|
||||
|
||||
proc_results->Tuple.variables[0] = make_entity_param(a, proc_scope, empty_token, t_i32, false);
|
||||
proc_results->Tuple.variables[0] = alloc_entity_param(proc_scope, empty_token, t_i32, false);
|
||||
|
||||
|
||||
Type *proc_type = alloc_type_proc(a, proc_scope,
|
||||
@@ -8649,7 +8639,7 @@ void ir_gen_tree(irGen *s) {
|
||||
proc_results, 1, false, ProcCC_Std);
|
||||
|
||||
AstNode *body = gb_alloc_item(a, AstNode);
|
||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||
Entity *e = alloc_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||
|
||||
m->entry_point_entity = e;
|
||||
@@ -8675,7 +8665,7 @@ void ir_gen_tree(irGen *s) {
|
||||
nullptr, 0, false,
|
||||
ProcCC_Contextless);
|
||||
AstNode *body = gb_alloc_item(a, AstNode);
|
||||
Entity *e = make_entity_procedure(a, nullptr, make_token_ident(name), proc_type, 0);
|
||||
Entity *e = alloc_entity_procedure(nullptr, make_token_ident(name), proc_type, 0);
|
||||
irValue *p = ir_value_procedure(a, m, e, proc_type, nullptr, body, name);
|
||||
|
||||
map_set(&m->values, hash_entity(e), p);
|
||||
|
||||
@@ -685,6 +685,8 @@ i32 exec_llvm_llc(String output_base) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int arg_count, char **arg_ptr) {
|
||||
if (arg_count < 2) {
|
||||
usage(make_string_c(arg_ptr[0]));
|
||||
|
||||
@@ -435,8 +435,12 @@ HashKey hash_cache_type_array(Type *elem, i64 count) {
|
||||
return hash_ptr_and_id(elem, cast(u64)count);
|
||||
}
|
||||
HashKey hash_cache_type_map(Type *key, Type *value) {
|
||||
u64 v = cast(u64)cast(uintptr)value;
|
||||
return hash_ptr_and_id(key, v);
|
||||
HashKey hkey = {};
|
||||
if ((key != nullptr) == (value != nullptr)) {
|
||||
u64 v = cast(u64)cast(uintptr)value;
|
||||
hkey = hash_ptr_and_id(key, v);
|
||||
}
|
||||
return hkey;
|
||||
}
|
||||
|
||||
|
||||
@@ -453,6 +457,7 @@ void init_cached_type_maps() {
|
||||
CachedType *find_cached_type(CachedTypeKind kind, HashKey key) {
|
||||
GB_ASSERT(key.kind == HashKey_PtrAndId);
|
||||
if (key.ptr_and_id.ptr == nullptr) {
|
||||
// NOTE(bill): uncachable types
|
||||
return nullptr;
|
||||
}
|
||||
auto *m = &cached_type_maps[kind];
|
||||
@@ -462,6 +467,7 @@ CachedType *find_cached_type(CachedTypeKind kind, HashKey key) {
|
||||
void add_cached_type(CachedTypeKind kind, HashKey key, Type *type) {
|
||||
GB_ASSERT(key.kind == HashKey_PtrAndId);
|
||||
if (key.ptr_and_id.ptr == nullptr) {
|
||||
// NOTE(bill): uncachable types
|
||||
return;
|
||||
}
|
||||
CachedType ct = {};
|
||||
@@ -1694,10 +1700,10 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
String data_str = str_lit("data");
|
||||
String type_info_str = str_lit("type_info");
|
||||
if (entity__any_data == nullptr) {
|
||||
entity__any_data = make_entity_field(a, nullptr, make_token_ident(data_str), t_rawptr, false, 0);
|
||||
entity__any_data = alloc_entity_field(nullptr, make_token_ident(data_str), t_rawptr, false, 0);
|
||||
}
|
||||
if (entity__any_type_info == nullptr) {
|
||||
entity__any_type_info = make_entity_field(a, nullptr, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
|
||||
entity__any_type_info = alloc_entity_field(nullptr, make_token_ident(type_info_str), t_type_info_ptr, false, 1);
|
||||
}
|
||||
|
||||
if (field_name == data_str) {
|
||||
@@ -1722,7 +1728,7 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
case (_length): \
|
||||
if (field_name == _name) { \
|
||||
selection_add_index(&sel, (_length)-1); \
|
||||
sel.entity = make_entity_array_elem(a, nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
||||
sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \
|
||||
return sel; \
|
||||
} \
|
||||
/*fallthrough*/
|
||||
@@ -1853,11 +1859,14 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
|
||||
}
|
||||
|
||||
|
||||
// IMPORTANT TODO(bill): SHould this TypePath code be removed since type cycle checking is handled much earlier on?
|
||||
|
||||
struct TypePath {
|
||||
Array<Entity *> path; // Entity_TypeName;
|
||||
bool failure;
|
||||
};
|
||||
|
||||
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user