From d02c5e1a21c8e7a720549bfcb77dd41e2839317c Mon Sep 17 00:00:00 2001 From: Abderrahim Indjaren Date: Mon, 18 May 2026 03:15:55 +0100 Subject: [PATCH] add: check duplicates in type switches --- src/check_expr.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- src/check_stmt.cpp | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e5b5623fe..51b7bb76b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9412,7 +9412,6 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op multi_map_insert(seen, key, tap); } - gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind upper_op, Operand const &x, Operand const &lhs, Operand const &rhs) { if (is_type_enum(x.type)) { // TODO(bill): Fix this logic so it's fast!!! @@ -9441,10 +9440,50 @@ gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, TokenKind u } } } + gb_internal void add_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { add_constant_switch_case(ctx, seen, x); } +gb_internal void add_type_switch_case(CheckerContext *ctx, SeenMap *seen, Operand operand) { + if (operand.mode != Addressing_Type) { + return ; + } + + uintptr key = type_hash_canonical_type(operand.type); + GB_ASSERT(key != 0); + + isize count = multi_map_count(seen, key); + if (count) { + TEMPORARY_ALLOCATOR_GUARD(); + TypeAndToken *taps = temporary_alloc_array(count); + + multi_map_get_all(seen, key, taps); + for (isize i = 0; i < count; i++) { + TypeAndToken tap = taps[i]; + if (!are_types_identical(tap.type, operand.type)) { + continue; + } + + TokenPos pos = tap.token.pos; + gbString expr_str = expr_to_string(operand.expr); + error(operand.expr, + "Duplicate case '%s'\n" + "\tprevious case at %s", + expr_str, + token_pos_to_string(pos)); + gb_string_free(expr_str); + } + } + + TypeAndToken tap = { operand.type, ast_token(operand.expr) }; + multi_map_insert(seen, key, tap); +} + +gb_internal void add_type_to_seen_map(CheckerContext *ctx, SeenMap *seen, Operand const &x) { + add_type_switch_case(ctx, seen, x); +} + gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ast_node(bd, BasicDirective, node); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d6987a332..04e9e9428 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1296,6 +1296,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags } t = default_type(t); add_type_info_type(ctx, t); + add_type_to_seen_map(ctx, &seen, y); } else { convert_to_typed(ctx, &y, x.type); if (y.mode == Addressing_Invalid) {