From 9543fbbf1ce302f0505742956b6f31d2e279e177 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 9 Jul 2023 01:00:39 +0200 Subject: [PATCH] Exhaustive switch on enums. This addresses #838 --- lib/std/core/allocators/arena_allocator.c3 | 1 - lib/std/core/allocators/dynamic_arena.c3 | 1 - lib/std/core/allocators/on_stack_allocator.c3 | 1 - lib/std/core/allocators/temp_allocator.c3 | 1 - lib/std/core/allocators/tracking_allocator.c3 | 1 - lib/std/encoding/json.c3 | 1 - releasenotes.md | 1 + src/compiler/sema_stmts.c | 7 +++- .../statements/exhaustive_switch.c3t | 39 +++++++++++++++++++ 9 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 test/test_suite/statements/exhaustive_switch.c3t diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index b8e81c853..5813c44ae 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -79,7 +79,6 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz arena.used = size; return null; } - unreachable(); } /** diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 79c955583..cf8ede153 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -237,5 +237,4 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm allocator.reset(); return null; } - unreachable(); } diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index ae49e93ac..985849e70 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -97,7 +97,6 @@ fn void*! on_stack_allocator_function(Allocator* data, usz size, usz alignment, case RESET: unreachable("Reset unsupported"); } - unreachable(); } fn bool allocation_in_stack_mem(OnStackAllocator* a, void* ptr) @local diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index c35b0d402..e92ad6a21 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -83,7 +83,6 @@ fn void*! temp_allocator_function(Allocator* data, usz size, usz alignment, usz arena._reset(size)!; return null; } - unreachable(); } fn void! TempAllocator._free(&self, void* old_pointer) @local diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 63098db10..dad34ba42 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -104,5 +104,4 @@ fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz of this.map.clear(); return null; } - unreachable(); } diff --git a/lib/std/encoding/json.c3 b/lib/std/encoding/json.c3 index 2a2bb4d56..c67ea97c7 100644 --- a/lib/std/encoding/json.c3 +++ b/lib/std/encoding/json.c3 @@ -69,7 +69,6 @@ fn Object*! JsonParser.parse_from_token(&self, JsonTokenType token) case NULL: return object::new_null(); case EOF: return JsonParsingError.EOF?; } - unreachable(); } fn Object*! JsonParser.parse_any(&self) { diff --git a/releasenotes.md b/releasenotes.md index 966340aa1..f2f483c5c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -3,6 +3,7 @@ ## 0.5.0 Change List ### Changes / improvements +- Exhaustive switches with enums has better analysis. - Globals may now be initialized with optional values. - New generic syntax. - Added `$embed` to embed binary data. diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 9bcd98980..0ed60dfeb 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2110,8 +2110,10 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc return false; } // We need an if-chain if this isn't an enum/integer type. - TypeKind flat_switch_type_kind = type_flatten(switch_type)->type_kind; - bool if_chain = flat_switch_type_kind != TYPE_ENUM && !type_kind_is_any_integer(flat_switch_type_kind); + Type *flat = type_flatten(switch_type); + TypeKind flat_switch_type_kind = flat->type_kind; + bool is_enum_switch = flat_switch_type_kind == TYPE_ENUM; + bool if_chain = !is_enum_switch && !type_kind_is_any_integer(flat_switch_type_kind); Ast *default_case = NULL; assert(context->active_scope.defer_start == context->active_scope.defer_last); @@ -2163,6 +2165,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc POP_NEXT(); } + if (!exhaustive && is_enum_switch && case_count == vec_size(flat->decl->enums.values)) exhaustive = true; bool all_jump_end = exhaustive; for (unsigned i = 0; i < case_count; i++) { diff --git a/test/test_suite/statements/exhaustive_switch.c3t b/test/test_suite/statements/exhaustive_switch.c3t new file mode 100644 index 000000000..562536d4e --- /dev/null +++ b/test/test_suite/statements/exhaustive_switch.c3t @@ -0,0 +1,39 @@ +// #target: macos-x64 +module test; +import std::io; + +enum Foo +{ + ABC, + DEF +} + +fn int hello(Foo a) +{ + switch (a) + { + case ABC: return 1; + case DEF: return 0; + } +} + +/* #expect: test.ll + +define i32 @test.hello(i32 %0) #0 { +entry: + %switch = alloca i32, align 4 + store i32 %0, ptr %switch, align 4 + br label %switch.entry +switch.entry: ; preds = %entry + %1 = load i32, ptr %switch, align 4 + switch i32 %1, label %switch.exit [ + i32 0, label %switch.case + i32 1, label %switch.case1 + ] +switch.case: ; preds = %switch.entry + ret i32 1 +switch.case1: ; preds = %switch.entry + ret i32 0 +switch.exit: ; preds = %switch.entry + unreachable +}