diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index f7cabab11..ab6535645 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -107,23 +107,24 @@ type_is_simple_compare :: proc($T: typeid) -> bool --- // easily compared using type_is_dereferenceable :: proc($T: typeid) -> bool --- type_is_valid_map_key :: proc($T: typeid) -> bool --- -type_is_named :: proc($T: typeid) -> bool --- -type_is_pointer :: proc($T: typeid) -> bool --- -type_is_opaque :: proc($T: typeid) -> bool --- -type_is_array :: proc($T: typeid) -> bool --- -type_is_slice :: proc($T: typeid) -> bool --- -type_is_dynamic_array :: proc($T: typeid) -> bool --- -type_is_map :: proc($T: typeid) -> bool --- -type_is_struct :: proc($T: typeid) -> bool --- -type_is_union :: proc($T: typeid) -> bool --- -type_is_enum :: proc($T: typeid) -> bool --- -type_is_proc :: proc($T: typeid) -> bool --- -type_is_bit_field :: proc($T: typeid) -> bool --- -type_is_bit_field_value :: proc($T: typeid) -> bool --- -type_is_bit_set :: proc($T: typeid) -> bool --- -type_is_simd_vector :: proc($T: typeid) -> bool --- +type_is_named :: proc($T: typeid) -> bool --- +type_is_pointer :: proc($T: typeid) -> bool --- +type_is_opaque :: proc($T: typeid) -> bool --- +type_is_array :: proc($T: typeid) -> bool --- +type_is_enumerated_array :: proc($T: typeid) -> bool --- +type_is_slice :: proc($T: typeid) -> bool --- +type_is_dynamic_array :: proc($T: typeid) -> bool --- +type_is_map :: proc($T: typeid) -> bool --- +type_is_struct :: proc($T: typeid) -> bool --- +type_is_union :: proc($T: typeid) -> bool --- +type_is_enum :: proc($T: typeid) -> bool --- +type_is_proc :: proc($T: typeid) -> bool --- +type_is_bit_field :: proc($T: typeid) -> bool --- +type_is_bit_field_value :: proc($T: typeid) -> bool --- +type_is_bit_set :: proc($T: typeid) -> bool --- +type_is_simd_vector :: proc($T: typeid) -> bool --- -type_has_nil :: proc($T: typeid) -> bool --- +type_has_nil :: proc($T: typeid) -> bool --- type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) --- type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) --- diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5f8a5be4f..70344339c 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -161,6 +161,8 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { } return; } + +#if 1 if (!is_type_constant_type(operand->type)) { gbString type_str = type_to_string(operand->type); error(operand->expr, "Invalid constant type: '%s'", type_str); @@ -170,6 +172,7 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { } return; } +#endif if (e->type == nullptr) { // NOTE(bill): type inference e->type = operand->type; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2776b8d6d..14b188cc0 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3144,6 +3144,74 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 return true; } + +ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selection sel, bool *success_) { + if (operand->mode != Addressing_Constant) { + if (success_) *success_ = false; + return empty_exact_value; + } + + if (sel.indirect) { + if (success_) *success_ = false; + return empty_exact_value; + } + + if (sel.index.count == 0) { + if (success_) *success_ = false; + return empty_exact_value; + } + + + ExactValue value = operand->value; + if (value.kind == ExactValue_Compound) { + i32 depth = 0; + while (sel.index.count > 0) { + i32 index = sel.index[0]; + sel = sub_selection(sel, 1); + + Ast *node = value.value_compound; + switch (node->kind) { + case_ast_node(cl, CompoundLit, node); + if (cl->elems.count == 0) { + if (success_) *success_ = true; + return empty_exact_value; + } + + if (cl->elems[0]->kind == Ast_FieldValue) { + GB_PANIC("TODO"); + } else { + i32 count = (i32)cl->elems.count; + if (count < index) { + if (success_) *success_ = false; + return empty_exact_value; + } + TypeAndValue tav = cl->elems[index]->tav; + if (tav.mode == Addressing_Constant) { + value = tav.value; + } else { + GB_ASSERT(is_type_untyped_nil(tav.type)); + value = tav.value; + } + } + + case_end; + + default: + if (success_) *success_ = true; + return empty_exact_value; + } + + depth += 1; + } + + if (success_) *success_ = true; + return value; + } + + if (success_) *success_ = true; + return empty_exact_value; +} + Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *type_hint) { ast_node(se, SelectorExpr, node); @@ -3291,6 +3359,39 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ } if (expr_entity != nullptr && expr_entity->kind == Entity_Constant && entity->kind != Entity_Constant) { + bool success = false; + ExactValue field_value = get_constant_field(c, operand, sel, &success); + if (success) { + operand->mode = Addressing_Constant; + operand->expr = node; + operand->value = field_value; + operand->type = entity->type; + return entity; + } + + gbString op_str = expr_to_string(op_expr); + gbString type_str = type_to_string(operand->type); + gbString sel_str = expr_to_string(selector); + error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str); + gb_string_free(sel_str); + gb_string_free(type_str); + gb_string_free(op_str); + operand->mode = Addressing_Invalid; + operand->expr = node; + return nullptr; + } + + if (operand->mode == Addressing_Constant && entity->kind != Entity_Constant) { + bool success = false; + ExactValue field_value = get_constant_field(c, operand, sel, &success); + if (success) { + operand->mode = Addressing_Constant; + operand->expr = node; + operand->value = field_value; + operand->type = entity->type; + return entity; + } + gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string(operand->type); gbString sel_str = expr_to_string(selector); @@ -3441,6 +3542,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_end - BuiltinProc__ty is_type_pointer, is_type_opaque, is_type_array, + is_type_enumerated_array, is_type_slice, is_type_dynamic_array, diff --git a/src/check_type.cpp b/src/check_type.cpp index 0b7843993..bdb5f048b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3234,7 +3234,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t if (o.mode == Addressing_Type && o.type->kind == Type_Generic) { generic_type = o.type; - } else if (is_type_enum(o.type)) { + } else if (o.mode == Addressing_Type && is_type_enum(o.type)) { Type *index = o.type; Type *bt = base_type(index); GB_ASSERT(bt->kind == Type_Enum); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 90c6963db..ffdaf43d7 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -142,6 +142,7 @@ BuiltinProc__type_begin, BuiltinProc_type_is_pointer, BuiltinProc_type_is_opaque, BuiltinProc_type_is_array, + BuiltinProc_type_is_enumerated_array, BuiltinProc_type_is_slice, BuiltinProc_type_is_dynamic_array, BuiltinProc_type_is_map, @@ -305,6 +306,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_pointer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_opaque"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_enumerated_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_slice"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_map"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/types.cpp b/src/types.cpp index f4423ba69..7c4e47f12 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -336,6 +336,14 @@ Selection selection_combine(Selection const &lhs, Selection const &rhs) { return new_sel; } +Selection sub_selection(Selection const &sel, isize offset) { + Selection res = {}; + res.index.data = sel.index.data + offset; + res.index.count = sel.index.count - offset; + res.index.capacity = res.index.count; + return res; +} + gb_global Type basic_types[] = {