mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-30 18:02:02 +00:00
@@ -1286,7 +1286,6 @@ bool check_cycle(CheckerContext *c, Entity *curr, bool report) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) {
|
||||
GB_ASSERT(n->kind == Ast_Ident);
|
||||
o->mode = Addressing_Invalid;
|
||||
@@ -1422,8 +1421,12 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
||||
case Entity_TypeName:
|
||||
o->mode = Addressing_Type;
|
||||
if (check_cycle(c, e, true)) {
|
||||
type = t_invalid;
|
||||
o->type = t_invalid;
|
||||
}
|
||||
if (o->type != nullptr && type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) {
|
||||
o->type = base_type(o->type);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Entity_ImportName:
|
||||
@@ -4064,6 +4067,98 @@ Type *determine_swizzle_array_type(Type *original_type, Type *type_hint, isize n
|
||||
}
|
||||
|
||||
|
||||
bool is_entity_declared_for_selector(Entity *entity, Scope *import_scope, bool *allow_builtin) {
|
||||
bool is_declared = entity != nullptr;
|
||||
if (is_declared) {
|
||||
if (entity->kind == Entity_Builtin) {
|
||||
// NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy
|
||||
// This means that we should just ignore the found result through it
|
||||
*allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope;
|
||||
} else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) {
|
||||
is_declared = false;
|
||||
}
|
||||
}
|
||||
return is_declared;
|
||||
}
|
||||
|
||||
// NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning
|
||||
Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node) {
|
||||
if (node->kind == Ast_Ident) {
|
||||
String name = node->Ident.token.string;
|
||||
return scope_lookup(c->scope, name);
|
||||
} else if (node->kind == Ast_SelectorExpr) {
|
||||
ast_node(se, SelectorExpr, node);
|
||||
if (!c->allow_arrow_right_selector_expr && se->token.kind == Token_ArrowRight) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Ast *op_expr = se->expr;
|
||||
Ast *selector = unparen_expr(se->selector);
|
||||
if (selector == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (selector->kind != Ast_Ident) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Entity *entity = nullptr;
|
||||
Entity *expr_entity = nullptr;
|
||||
bool check_op_expr = true;
|
||||
|
||||
if (op_expr->kind == Ast_Ident) {
|
||||
String op_name = op_expr->Ident.token.string;
|
||||
Entity *e = scope_lookup(c->scope, op_name);
|
||||
add_entity_use(c, op_expr, e);
|
||||
expr_entity = e;
|
||||
|
||||
if (e != nullptr && e->kind == Entity_ImportName && selector->kind == Ast_Ident) {
|
||||
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
|
||||
// It pretty much needs to be in this order and this way
|
||||
// If you can clean this up, please do but be really careful
|
||||
String import_name = op_name;
|
||||
Scope *import_scope = e->ImportName.scope;
|
||||
String entity_name = selector->Ident.token.string;
|
||||
|
||||
check_op_expr = false;
|
||||
entity = scope_lookup_current(import_scope, entity_name);
|
||||
bool allow_builtin = false;
|
||||
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
check_entity_decl(c, entity, nullptr, nullptr);
|
||||
if (entity->kind == Entity_ProcGroup) {
|
||||
return entity;
|
||||
}
|
||||
GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind]));
|
||||
}
|
||||
}
|
||||
|
||||
Operand operand = {};
|
||||
if (check_op_expr) {
|
||||
check_expr_base(c, &operand, op_expr, nullptr);
|
||||
if (operand.mode == Addressing_Invalid) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == nullptr && selector->kind == Ast_Ident) {
|
||||
String field_name = selector->Ident.token.string;
|
||||
if (is_type_dynamic_array(type_deref(operand.type))) {
|
||||
init_mem_allocator(c->checker);
|
||||
}
|
||||
auto sel = lookup_field(operand.type, field_name, operand.mode == Addressing_Type);
|
||||
entity = sel.entity;
|
||||
}
|
||||
|
||||
if (entity != nullptr) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *type_hint) {
|
||||
ast_node(se, SelectorExpr, node);
|
||||
|
||||
@@ -4112,18 +4207,8 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
check_op_expr = false;
|
||||
entity = scope_lookup_current(import_scope, entity_name);
|
||||
bool is_declared = entity != nullptr;
|
||||
bool allow_builtin = false;
|
||||
if (is_declared) {
|
||||
if (entity->kind == Entity_Builtin) {
|
||||
// NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy
|
||||
// This means that we should just ignore the found result through it
|
||||
allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope;
|
||||
} else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) {
|
||||
is_declared = false;
|
||||
}
|
||||
}
|
||||
if (!is_declared) {
|
||||
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
||||
error(op_expr, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
@@ -4213,7 +4298,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) {
|
||||
if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) {
|
||||
// TODO(bill): Simd_Vector swizzling
|
||||
|
||||
String field_name = selector->Ident.token.string;
|
||||
|
||||
Reference in New Issue
Block a user