diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fd01f8cf7..45fa8b7f7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5759,6 +5759,134 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v +gb_internal Ast *constant_compound_elem_node(AstCompoundLit *cl, i64 index) { + if (cl->elems.count == 0) { + return nullptr; + } + if (cl->elems[0]->kind != Ast_FieldValue) { + return index < cl->elems.count ? cl->elems[index] : nullptr; + } + for (Ast *elem : cl->elems) { + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + i64 lo = exact_value_to_i64(ie->left->tav.value); + i64 hi = exact_value_to_i64(ie->right->tav.value); + if (ie->op.kind != Token_RangeHalf) { + hi += 1; + } + if (lo <= index && index < hi) { + return fv->value; + } + } else if (fv->field->tav.mode == Addressing_Constant && exact_value_to_i64(fv->field->tav.value) == index) { + return fv->value; + } + } + return nullptr; +} + +gb_internal ExactValue get_constant_soa_field(Type *soa, ExactValue value, Selection sel, bool *success_) { + if (success_) *success_ = false; + + Type *elem = base_type(soa->Struct.soa_elem); + if (sel.index.count != 1 || soa->Struct.soa_kind != StructSoa_Fixed || + value.value_compound->kind != Ast_CompoundLit || + !(elem->kind == Type_Array || (elem->kind == Type_Struct && !elem->Struct.is_raw_union))) { + return empty_exact_value; + } + + i32 field_index = sel.index[0]; + Entity *field = soa->Struct.fields[field_index]; + + Type *field_elem_type = base_type(field->type)->Array.elem; + + isize count = soa->Struct.soa_count; + Ast *soa_node = value.value_compound; + + AstFile *f = soa_node->file(); + ast_node(cl, CompoundLit, soa_node); + + auto nodes = permanent_slice_make(count); + + isize last = -1; + bool has_gaps = false; + + for (isize i = 0; i < count; i++) { + Ast *en = constant_compound_elem_node(cl, i); + if (en == nullptr || en->tav.value.kind == ExactValue_Invalid) { + continue; + } + ExactValue ev = en->tav.value; + if (ev.kind != ExactValue_Compound || ev.value_compound->kind != Ast_CompoundLit) { + return empty_exact_value; + } + ast_node(ecl, CompoundLit, ev.value_compound); + + Ast *fn = nullptr; + if (elem->kind == Type_Struct && ecl->elems.count > 0 && ecl->elems[0]->kind == Ast_FieldValue) { + for (Ast *e : ecl->elems) { + ast_node(fv, FieldValue, e); + if (fv->field->kind == Ast_Ident && fv->field->Ident.token.string == field->token.string) { + fn = fv->value; + break; + } + } + } else { + fn = constant_compound_elem_node(ecl, field_index); + } + if (fn == nullptr) { + continue; + } + + ExactValue fvalue = fn->tav.value; + if (fn->tav.mode == Addressing_Type) { + fvalue = exact_value_typeid(fn->tav.type); + } + if (fvalue.kind == ExactValue_Invalid) { + continue; + } + + Ast *node = alloc_ast_node(nullptr, fn->kind); + gb_memmove(node, fn, ast_node_size(fn->kind)); + node->tav.mode = Addressing_Constant; + node->tav.type = field_elem_type; + node->tav.value = fvalue; + + nodes[i] = node; + has_gaps |= last+1 != i; + last = i; + } + + auto elems = array_make(permanent_allocator(), 0, last+1); + for (isize i = 0; i <= last; i++) { + if (!has_gaps) { + array_add(&elems, nodes[i]); + } else if (nodes[i] != nullptr) { + Token token = {Token_Integer}; + token.string = copy_string(permanent_allocator(), make_string_c(gb_bprintf("%td", i))); + token.pos = ast_token(nodes[i]).pos; + + Ast *index = alloc_ast_node(f, Ast_BasicLit); + index->BasicLit.token = token; + index->tav.mode = Addressing_Constant; + index->tav.type = t_untyped_integer; + index->tav.value = exact_value_i64(i); + + Token eq = {Token_Eq}; + eq.string = str_lit("="); + array_add(&elems, ast_field_value(f, index, nodes[i], eq)); + } + } + + Ast *result = ast_compound_lit(f, nullptr, elems, cl->open, cl->close); + result->tav.mode = Addressing_Constant; + result->tav.type = field->type; + result->tav.value = exact_value_compound(result); + + if (success_) *success_ = true; + return result->tav.value; +} + gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *operand, Selection sel, bool *success_) { if (operand->mode != Addressing_Constant) { if (success_) *success_ = false; @@ -5777,6 +5905,9 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper ExactValue value = operand->value; + if (value.kind == ExactValue_Compound && is_type_soa_struct(operand->type)) { + return get_constant_soa_field(base_type(operand->type), value, sel, success_); + } if (value.kind == ExactValue_Compound) { while (sel.index.count > 0) { i32 index = sel.index[0]; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index e1266ff01..b2f855e25 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -823,6 +823,7 @@ gb_internal i32 exact_value_order(ExactValue const &v) { case ExactValue_Pointer: return 7; case ExactValue_Procedure: + case ExactValue_Typeid: return 8; default: diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 12b1f23cf..46bf5fb31 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -571,6 +571,10 @@ gb_internal void write_canonical_exact_value(TypeWriter *w, ExactValue const &v) return; } } + if (v.kind == ExactValue_Typeid) { + write_type_to_canonical_string(w, v.value_typeid); + return; + } gbString s = exact_value_to_string(v, 1<<16); type_writer_append(w, s, gb_string_length(s)); gb_string_free(s); diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 1c68c582d..a8d9a2b64 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -86,6 +86,7 @@ clang -c ..\test_issue_sysv_abi.c -o test_issue_sysv_abi_c.o || exit /b ..\..\..\odin test ..\test_issue_poly_using_subtype.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_7708.odin %COMMON% || exit /b ..\..\..\odin check ..\test_issue_7708_mismatch.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b +..\..\..\odin test ..\test_issue_7700.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_7587.odin %COMMON% || exit /b ..\..\..\odin run ..\test_issue_7596.odin %COMMON% || exit /b diff --git a/tests/issues/run.sh b/tests/issues/run.sh index e8912b635..2d9b70b34 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -112,6 +112,7 @@ else echo "SUCCESSFUL 0/1" exit 1 fi +$ODIN test ../test_issue_7700.odin $COMMON $ODIN test ../test_issue_7587.odin $COMMON $ODIN run ../test_issue_7596.odin $COMMON $ODIN test ../test_issue_7421.odin $COMMON