From 08eb19456b319cc5b0c287773d52850f12f2bcb5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 11 Feb 2016 16:15:08 -0700 Subject: [PATCH] add compile error for missing enumeration value in switch --- src/analyze.cpp | 25 +++++++++++++++++++++++++ test/run_tests.cpp | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/analyze.cpp b/src/analyze.cpp index 8d1091392..02056c1be 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4241,6 +4241,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true); } else if (buf_eql_str(&var_name, "is_test")) { return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true); + } else if (buf_eql_str(&var_name, "os")) { + zig_panic("TODO"); } else { add_node_error(g, *str_node, buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name))); @@ -4650,6 +4652,11 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, buf_sprintf("switch on unreachable expression not allowed")); return g->builtin_types.entry_invalid; } else { + int *field_use_counts = nullptr; + if (expr_type->id == TypeTableEntryIdEnum) { + field_use_counts = allocate(expr_type->data.enumeration.field_count); + } + AstNode *else_prong = nullptr; for (int prong_i = 0; prong_i < prong_count; prong_i += 1) { AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); @@ -4686,6 +4693,14 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, if (type_enum_field->type_entry != var_type) { all_agree_on_var_type = false; } + uint32_t field_index = type_enum_field->value; + assert(field_use_counts); + field_use_counts[field_index] += 1; + if (field_use_counts[field_index] > 1) { + add_node_error(g, item_node, + buf_sprintf("duplicate switch value: '%s'", + buf_ptr(type_enum_field->name))); + } } else { add_node_error(g, item_node, buf_sprintf("enum '%s' has no field '%s'", @@ -4729,6 +4744,16 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, prong_node->data.switch_prong.expr); peer_nodes[prong_i] = prong_node->data.switch_prong.expr; } + + if (expr_type->id == TypeTableEntryIdEnum && !else_prong) { + for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) { + if (field_use_counts[i] == 0) { + add_node_error(g, node, + buf_sprintf("enumeration value '%s' not handled in switch", + buf_ptr(expr_type->data.enumeration.fields[i].name))); + } + } + } } return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 333813419..b372473ee 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1760,6 +1760,23 @@ const float_x = f32(1.0) / f32(0.0); ".tmp_source.zig:3:25: error: division by zero is undefined", ".tmp_source.zig:4:22: error: division by zero is undefined", ".tmp_source.zig:5:26: error: division by zero is undefined"); + + + add_compile_fail_case("missing switch prong", R"SOURCE( +enum Number { + One, + Two, + Three, + Four, +} +fn f(n: Number) -> i32 { + switch (n) { + One => 1, + Two => 2, + Three => 3, + } +} + )SOURCE", 1, ".tmp_source.zig:9:5: error: enumeration value 'Four' not handled in switch"); } //////////////////////////////////////////////////////////////////////////////