From edeca40dd6be5765be6d2f2d8dcfb1ff05d51d26 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 7 Oct 2026 13:41:32 +0100 Subject: [PATCH] Skip the escape analysis for an executable's entry point, suggest clearing stores, and add `type_zero_value_string` --- src/check_escape.cpp | 9 +------- src/check_expr.cpp | 18 +--------------- src/types.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/check_escape.cpp b/src/check_escape.cpp index 47ceebecb..586a3b160 100644 --- a/src/check_escape.cpp +++ b/src/check_escape.cpp @@ -1144,14 +1144,7 @@ gb_internal void escape_report(EscapeAnalysis *ea, Ast *node, String expr_str, E } if (kind == EscapeReport_Store) { - char const *zero = "{}"; - Type *t = node->tav.type; - if (t != nullptr && type_has_nil(t)) { - zero = "nil"; - } else if (t != nullptr && is_type_string(t)) { - zero = "\"\""; - } - error_line("\tSuggestion: Clear it before the procedure returns, e.g. 'defer %.*s = %s'\n", LIT(expr_str), zero); + error_line("\tSuggestion: Clear it before the procedure returns, e.g. 'defer %.*s = %s'\n", LIT(expr_str), type_zero_value_string(node->tav.type)); } else { error_line("\tSuggestion: If this is intended, make it explicit with a conversion to 'rawptr' or 'uintptr', or a 'transmute'\n"); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6cbf41ef6..4e1db0075 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2741,23 +2741,7 @@ gb_internal char const *zero_value_suggestion(Operand *o, Type *type) { if (!is_exact_value_zero(o->value)) { return nullptr; } - - char const *suggestion = nullptr; - if (is_type_string(type)) { - suggestion = "\"\""; - } else if (is_type_boolean(type)) { - suggestion = "false"; - } else if (is_type_bit_set(type)) { - // A bit_set accepts both `nil` and `{}`. `{}` is a bit more idiomatic - // because `{.Something}` becomes `{}` when no bits are set. - suggestion = "{}"; - } else if (type_has_nil(type)) { - suggestion = "nil"; - } else { - suggestion = "{}"; - } - - return suggestion; + return type_zero_value_string(type); } gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size) { diff --git a/src/types.cpp b/src/types.cpp index 3a8268271..bebdae18d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2753,6 +2753,55 @@ gb_internal bool type_has_nil(Type *t) { return false; } +gb_internal char const *type_zero_value_string(Type *t) { + t = base_type(t); + if (t == nullptr) { + return "{}"; + } + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + case Basic_string16: + case Basic_UntypedString: + return "\"\""; + case Basic_rawptr: + case Basic_cstring: + case Basic_cstring16: + case Basic_any: + case Basic_typeid: + case Basic_UntypedNil: + return "nil"; + } + if (t->Basic.flags & BasicFlag_Boolean) { + return "false"; + } + if (t->Basic.flags & (BasicFlag_Numeric|BasicFlag_Rune)) { + return "0"; + } + return "{}"; + + case Type_Pointer: + case Type_MultiPointer: + case Type_SoaPointer: + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + case Type_Proc: + return "nil"; + + case Type_Union: + case Type_Struct: + // a union without #no_nil, or a #soa slice or dynamic array + if (type_has_nil(t)) { + return "nil"; + } + return "{}"; + } + // an enum or bit_set may also be 'nil', but '{}' reads better + return "{}"; +} + gb_internal bool is_type_union_constantable(Type *type); gb_internal bool is_type_constant_type_for_unions(Type *t) {