From 9395162a7c41689bcd1c0c48f9eabffc1485fc74 Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Mon, 2 Jul 2018 16:56:40 -0400 Subject: [PATCH 1/3] Debug enum issue --- src/ir.cpp | 1 + test/behavior.zig | 1 + test/cases/switch_usize_enum_prongs.zig | 11 +++++++++++ 3 files changed, 13 insertions(+) create mode 100644 test/cases/switch_usize_enum_prongs.zig diff --git a/src/ir.cpp b/src/ir.cpp index b40c2dc36d8f927e153ca09ad1446e33d10e831f..c16f3c09b86877620159ea7f1077f99f81c1ea75 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19149,6 +19149,7 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira if (!end_val) return ira->codegen->builtin_types.entry_invalid; + printf("%s\n", buf_ptr(&start_val->type->name)); assert(start_val->type->id == TypeTableEntryIdInt || start_val->type->id == TypeTableEntryIdComptimeInt); assert(end_val->type->id == TypeTableEntryIdInt || end_val->type->id == TypeTableEntryIdComptimeInt); AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, diff --git a/test/behavior.zig b/test/behavior.zig index d47eb8fd6cb9883fc7baccf4c1eddf15727922c2..803d4a5a083638e9c11c5290e3ecb69546876a22 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -52,6 +52,7 @@ comptime { _ = @import("cases/switch.zig"); _ = @import("cases/switch_prong_err_enum.zig"); _ = @import("cases/switch_prong_implicit_cast.zig"); + _ = @import("cases/switch_usize_enum_prongs.zig"); _ = @import("cases/syntax.zig"); _ = @import("cases/this.zig"); _ = @import("cases/try.zig"); diff --git a/test/cases/switch_usize_enum_prongs.zig b/test/cases/switch_usize_enum_prongs.zig new file mode 100644 index 0000000000000000000000000000000000000000..b49615e887c76a3fc1a86204090bfb44848cd0d2 --- /dev/null +++ b/test/cases/switch_usize_enum_prongs.zig @@ -0,0 +1,11 @@ +const E = enum(usize) { One, Two }; + +test "aoeou" { + foo(1); +} + +fn foo(x: usize) void { + switch (x) { + E.One => {}, + } +} -- 2.54.0 From 9cff23dbf9ff3da716a1c4397f9411eba09f6cac Mon Sep 17 00:00:00 2001 From: Isaac Hier Date: Wed, 4 Jul 2018 13:27:10 -0400 Subject: [PATCH 2/3] Fix assertion crash on enum switch values --- src/ir.cpp | 7 ++++++- test/behavior.zig | 1 - test/cases/switch_usize_enum_prongs.zig | 11 ----------- test/compile_errors.zig | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 13 deletions(-) delete mode 100644 test/cases/switch_usize_enum_prongs.zig diff --git a/src/ir.cpp b/src/ir.cpp index c16f3c09b86877620159ea7f1077f99f81c1ea75..37d673bbd71e9668c722de693be9657304def543 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19149,9 +19149,14 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira if (!end_val) return ira->codegen->builtin_types.entry_invalid; - printf("%s\n", buf_ptr(&start_val->type->name)); + if (start_val->type->id == TypeTableEntryIdEnum) + return ira->codegen->builtin_types.entry_invalid; assert(start_val->type->id == TypeTableEntryIdInt || start_val->type->id == TypeTableEntryIdComptimeInt); + + if (end_val->type->id == TypeTableEntryIdEnum) + return ira->codegen->builtin_types.entry_invalid; assert(end_val->type->id == TypeTableEntryIdInt || end_val->type->id == TypeTableEntryIdComptimeInt); + AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, start_value->source_node); if (prev_node != nullptr) { diff --git a/test/behavior.zig b/test/behavior.zig index 803d4a5a083638e9c11c5290e3ecb69546876a22..d47eb8fd6cb9883fc7baccf4c1eddf15727922c2 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -52,7 +52,6 @@ comptime { _ = @import("cases/switch.zig"); _ = @import("cases/switch_prong_err_enum.zig"); _ = @import("cases/switch_prong_implicit_cast.zig"); - _ = @import("cases/switch_usize_enum_prongs.zig"); _ = @import("cases/syntax.zig"); _ = @import("cases/this.zig"); _ = @import("cases/try.zig"); diff --git a/test/cases/switch_usize_enum_prongs.zig b/test/cases/switch_usize_enum_prongs.zig deleted file mode 100644 index b49615e887c76a3fc1a86204090bfb44848cd0d2..0000000000000000000000000000000000000000 --- a/test/cases/switch_usize_enum_prongs.zig +++ /dev/null @@ -1,11 +0,0 @@ -const E = enum(usize) { One, Two }; - -test "aoeou" { - foo(1); -} - -fn foo(x: usize) void { - switch (x) { - E.One => {}, - } -} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7291a48a8fd7015ffdd6f9882e828d88b1d3c5ef..8bd5480395b43122513e22c5fa83a155f5f7f709 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -358,6 +358,24 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ".tmp_source.zig:3:14: note: other value is here", ); + + cases.add( + "invalid cast from integral type to enum", + \\const E = enum(usize) { One, Two }; + \\ + \\export fn entry() void { + \\ foo(1); + \\} + \\ + \\fn foo(x: usize) void { + \\ switch (x) { + \\ E.One => {}, + \\ } + \\} + , + ".tmp_source.zig:9:10: error: expected type 'usize', found 'E'" + ); + cases.add( "range operator in switch used on error set", \\export fn entry() void { -- 2.54.0 From 1a5bd8888174ef2eb1881c1dd81d418b44625cc7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 6 Jul 2018 12:03:07 -0400 Subject: [PATCH 3/3] alternate implementation of previous commit This strategy adds another field to the SwitchBr instruction, which is the result of the CheckSwitchProngs instruction. The type of the result is void, and is unused, except that the SwitchBr instruction will not perform analysis if the CheckSwitchProngs instruction did not pass analysis. This allows the CheckSwitchProngs instruction to do implicit casting for its type checking, while preventing duplicate compile error messages. --- src/all_types.hpp | 1 + src/ir.cpp | 44 +++++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 5d449491c8e9fc854aaa2fe45cb36b8fec8260b0..4d97be468cfc1da29e56857d8dab9c7c1fb2199e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2193,6 +2193,7 @@ struct IrInstructionSwitchBr { size_t case_count; IrInstructionSwitchBrCase *cases; IrInstruction *is_comptime; + IrInstruction *switch_prongs_void; }; struct IrInstructionSwitchVar { diff --git a/src/ir.cpp b/src/ir.cpp index 37d673bbd71e9668c722de693be9657304def543..204ebb332a2554ed34d04e446a2be536936b84a4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1719,7 +1719,8 @@ static IrInstruction *ir_build_ctz_from(IrBuilder *irb, IrInstruction *old_instr } static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value, - IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime) + IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime, + IrInstruction *switch_prongs_void) { IrInstructionSwitchBr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable; @@ -1729,10 +1730,12 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode * instruction->case_count = case_count; instruction->cases = cases; instruction->is_comptime = is_comptime; + instruction->switch_prongs_void = switch_prongs_void; ir_ref_instruction(target_value, irb->current_basic_block); if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); ir_ref_bb(else_block); + if (switch_prongs_void) ir_ref_instruction(switch_prongs_void, irb->current_basic_block); for (size_t i = 0; i < case_count; i += 1) { ir_ref_instruction(cases[i].value, irb->current_basic_block); @@ -1744,10 +1747,10 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode * static IrInstruction *ir_build_switch_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *target_value, IrBasicBlock *else_block, size_t case_count, - IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime) + IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime, IrInstruction *switch_prongs_void) { IrInstruction *new_instruction = ir_build_switch_br(irb, old_instruction->scope, old_instruction->source_node, - target_value, else_block, case_count, cases, is_comptime); + target_value, else_block, case_count, cases, is_comptime, switch_prongs_void); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } @@ -6035,13 +6038,13 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * } - ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length, + IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length, else_prong != nullptr); if (cases.length == 0) { ir_build_br(irb, scope, node, else_block, is_comptime); } else { - ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime); + ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void); } if (!else_prong) { @@ -6692,7 +6695,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1); cases[1].block = cleanup_block; ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block, - 2, cases, const_bool_false); + 2, cases, const_bool_false, nullptr); ir_set_cursor_at_end_and_append_block(irb, cleanup_block); ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); @@ -6773,7 +6776,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1)); cases[1].block = cleanup_block; ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block, - 2, cases, const_bool_false)); + 2, cases, const_bool_false, nullptr)); ir_set_cursor_at_end_and_append_block(irb, cleanup_block); ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); @@ -7078,7 +7081,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec cases[0].block = invalid_resume_block; cases[1].value = ir_build_const_u8(irb, scope, node, 1); cases[1].block = irb->exec->coro_final_cleanup_block; - ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false); + ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr); ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block); ir_build_coro_end(irb, scope, node); @@ -15297,6 +15300,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, if (type_is_invalid(target_value->value.type)) return ir_unreach_error(ira); + if (switch_br_instruction->switch_prongs_void != nullptr) { + if (type_is_invalid(switch_br_instruction->switch_prongs_void->other->value.type)) { + return ir_unreach_error(ira); + } + } + + size_t case_count = switch_br_instruction->case_count; bool is_comptime; @@ -15387,7 +15397,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base); ir_build_switch_br_from(&ira->new_irb, &switch_br_instruction->base, - target_value, new_else_block, case_count, cases, nullptr); + target_value, new_else_block, case_count, cases, nullptr, nullptr); return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); } @@ -19136,27 +19146,27 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira IrInstruction *start_value = range->start->other; if (type_is_invalid(start_value->value.type)) return ira->codegen->builtin_types.entry_invalid; + IrInstruction *casted_start_value = ir_implicit_cast(ira, start_value, switch_type); + if (type_is_invalid(casted_start_value->value.type)) + return ira->codegen->builtin_types.entry_invalid; IrInstruction *end_value = range->end->other; if (type_is_invalid(end_value->value.type)) return ira->codegen->builtin_types.entry_invalid; + IrInstruction *casted_end_value = ir_implicit_cast(ira, end_value, switch_type); + if (type_is_invalid(casted_end_value->value.type)) + return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *start_val = ir_resolve_const(ira, start_value, UndefBad); + ConstExprValue *start_val = ir_resolve_const(ira, casted_start_value, UndefBad); if (!start_val) return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *end_val = ir_resolve_const(ira, end_value, UndefBad); + ConstExprValue *end_val = ir_resolve_const(ira, casted_end_value, UndefBad); if (!end_val) return ira->codegen->builtin_types.entry_invalid; - if (start_val->type->id == TypeTableEntryIdEnum) - return ira->codegen->builtin_types.entry_invalid; assert(start_val->type->id == TypeTableEntryIdInt || start_val->type->id == TypeTableEntryIdComptimeInt); - - if (end_val->type->id == TypeTableEntryIdEnum) - return ira->codegen->builtin_types.entry_invalid; assert(end_val->type->id == TypeTableEntryIdInt || end_val->type->id == TypeTableEntryIdComptimeInt); - AstNode *prev_node = rangeset_add_range(&rs, &start_val->data.x_bigint, &end_val->data.x_bigint, start_value->source_node); if (prev_node != nullptr) { -- 2.54.0