diff options
Diffstat (limited to 'src/check_stmt.cpp')
| -rw-r--r-- | src/check_stmt.cpp | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index fcd87e1a5..4e6623fc1 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1184,6 +1184,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ return; } + + Ast *nil_seen = nullptr; PtrSet<Type *> seen = {}; defer (ptr_set_destroy(&seen)); @@ -1194,6 +1196,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ } ast_node(cc, CaseClause, stmt); + bool saw_nil = false; // TODO(bill): Make robust Type *bt = base_type(type_deref(x.type)); @@ -1202,6 +1205,25 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ if (type_expr != nullptr) { // Otherwise it's a default expression Operand y = {}; check_expr_or_type(ctx, &y, type_expr); + + if (is_operand_nil(y)) { + if (!type_has_nil(type_deref(x.type))) { + error(type_expr, "'nil' case is not allowed for the type '%s'", type_to_string(type_deref(x.type))); + continue; + } + saw_nil = true; + + if (nil_seen) { + ERROR_BLOCK(); + error(type_expr, "'nil' case has already been handled previously"); + error_line("\t 'nil' was already previously seen at %s", token_pos_to_string(ast_token(nil_seen).pos)); + } else { + nil_seen = type_expr; + } + case_type = y.type; + continue; + } + if (y.mode != Addressing_Type) { gbString str = expr_to_string(type_expr); error(type_expr, "Expected a type as a case, got %s", str); @@ -1255,14 +1277,16 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ is_reference = true; } - if (cc->list.count > 1) { + if (cc->list.count > 1 || saw_nil) { case_type = nullptr; } if (case_type == nullptr) { case_type = x.type; } if (switch_kind == TypeSwitch_Any) { - add_type_info_type(ctx, case_type); + if (!is_type_untyped(case_type)) { + add_type_info_type(ctx, case_type); + } } check_open_scope(ctx, stmt); |