Skip to content

Commit

Permalink
Exhaustive switch on enums. This addresses #838
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Jul 8, 2023
1 parent 8b605d9 commit 9543fbb
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 8 deletions.
1 change: 0 additions & 1 deletion lib/std/core/allocators/arena_allocator.c3
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz
arena.used = size;
return null;
}
unreachable();
}

/**
Expand Down
1 change: 0 additions & 1 deletion lib/std/core/allocators/dynamic_arena.c3
Original file line number Diff line number Diff line change
Expand Up @@ -237,5 +237,4 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm
allocator.reset();
return null;
}
unreachable();
}
1 change: 0 additions & 1 deletion lib/std/core/allocators/on_stack_allocator.c3
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion lib/std/core/allocators/temp_allocator.c3
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion lib/std/core/allocators/tracking_allocator.c3
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,4 @@ fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz of
this.map.clear();
return null;
}
unreachable();
}
1 change: 0 additions & 1 deletion lib/std/encoding/json.c3
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
1 change: 1 addition & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions src/compiler/sema_stmts.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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++)
{
Expand Down
39 changes: 39 additions & 0 deletions test/test_suite/statements/exhaustive_switch.c3t
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 9543fbb

Please sign in to comment.