diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2025-12-01 11:53:08 +0000 |
|---|---|---|
| committer | gingerBill <gingerBill@users.noreply.github.com> | 2025-12-01 11:53:08 +0000 |
| commit | 3771ff7b123bf1debe2da2886d833791ee890b39 (patch) | |
| tree | 69cc14a85ef5cb47ede1280df76f6206aa934d00 /src/check_expr.cpp | |
| parent | 9f80d697027a41a9c36b8eb42d9c98f9b7fcbe2c (diff) | |
| parent | e72aad983bb683858a1aee935b2956ced40f69f8 (diff) | |
Merge branch 'master' into vendor/curl
Diffstat (limited to 'src/check_expr.cpp')
| -rw-r--r-- | src/check_expr.cpp | 115 |
1 files changed, 113 insertions, 2 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e22f12323..418fb5378 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9200,6 +9200,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A return kind; } + +gb_internal void check_expr_as_value_for_ternary(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { + check_expr_base(c, o, e, type_hint); + check_not_tuple(c, o); + error_operand_no_value(o); + + switch (o->mode) { + case Addressing_Type: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A type '%s' cannot be used as a runtime value", expr_str); + + error_line("\tSuggestion: If a runtime 'typeid' is wanted, use 'typeid_of' to convert a type\n"); + + o->mode = Addressing_Invalid; + + } break; + + case Addressing_Builtin: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A built-in procedure '%s' cannot be used as a runtime value", expr_str); + + error_line("\tNote: Built-in procedures are implemented by the compiler and might not be actually instantiated procedures\n"); + + o->mode = Addressing_Invalid; + } break; + + case Addressing_ProcGroup: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "Cannot use overloaded procedure '%s' as a runtime value", expr_str); + + error_line("\tNote: Please specify which procedure in the procedure group to use, via cast or type inference\n"); + + o->mode = Addressing_Invalid; + } break; + } +} + gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; Operand cond = {Addressing_Invalid}; @@ -9213,7 +9259,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - check_expr_or_type(c, &x, te->x, type_hint); + check_expr_as_value_for_ternary(c, &x, te->x, type_hint); node->viral_state_flags |= te->x->viral_state_flags; if (te->y != nullptr) { @@ -9221,7 +9267,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n if (type_hint == nullptr && is_type_typed(x.type)) { th = x.type; } - check_expr_or_type(c, &y, te->y, th); + check_expr_as_value_for_ternary(c, &y, te->y, th); node->viral_state_flags |= te->y->viral_state_flags; } else { error(node, "A ternary expression must have an else clause"); @@ -9248,6 +9294,20 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } + if (x.mode == Addressing_Builtin && y.mode == Addressing_Builtin) { + if (type_hint == nullptr) { + error(node, "Built-in procedures cannot be used within a ternary expression since they have no well-defined signature"); + return kind; + } + } + + if (x.mode == Addressing_ProcGroup && y.mode == Addressing_ProcGroup) { + if (type_hint == nullptr) { + error(node, "Procedure groups cannot be used within a ternary expression since they have no well-defined signature that can be inferred without a context"); + return kind; + } + } + // NOTE(bill, 2023-01-30): Allow for expression like this: // x: union{f32} = f32(123) if cond else nil if (type_hint && !is_type_any(type_hint)) { @@ -9778,6 +9838,57 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As c->bit_field_bit_size = prev_bit_field_bit_size; } + + if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) { + PtrSet<Entity *> missing_fields = {}; + defer (ptr_set_destroy(&missing_fields)); + + for_array(i, bt->Struct.fields) { + Entity *field = bt->Struct.fields[i]; + String name = field->token.string; + if (is_blank_ident(name) || name == "") { + continue; + } + bool found = string_set_exists(&fields_visited, name); + String *raw_union = string_map_get(&fields_visited_through_raw_union, name); + if (!found && raw_union == nullptr) { + ptr_set_add(&missing_fields, field); + } + } + + if (missing_fields.count > 0) { + Ast *expr = o->expr; + if (expr == nullptr) { + GB_ASSERT(elems.count > 0); + expr = elems[elems.count-1]; + } + + ERROR_BLOCK(); + + if (build_context.terse_errors) { + gbString fields_string = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(fields_string)); + isize i = 0; + FOR_PTR_SET(field, missing_fields) { + if (i > 0) { + fields_string = gb_string_appendc(fields_string, ", "); + } + String name = field->token.string; + fields_string = gb_string_append_length(fields_string, name.text, name.len); + i += 1; + } + + error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string); + } else { + error(expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:"); + FOR_PTR_SET(field, missing_fields) { + gbString s = type_to_string(field->type); + error_line("\t%.*s: %s\n", LIT(field->token.string), s); + gb_string_free(s); + } + } + } + } } gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { |