authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-03 23:40:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-03 23:40:47-04:00
logbfe0bf695b8471a5553bf5cdf5fc527c42eda1e8
tree028b4b233b826f31a6ffc95c8d58a7314529c904
parentc2cf04086a74a3c0ac31dbc1b8d01de76988c7ae
parenta1b952f4b03b7becad85ad47f96a75c0be620cf8
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'impl-1107' of https://github.com/emekoi/zig into emekoi-impl-1107


4 files changed, 73 insertions(+), 6 deletions(-)

doc/langref.html.in+4-2
......@@ -3016,6 +3016,7 @@ test "switch on tagged union" {
30163016 A: u32,
30173017 C: Point,
30183018 D,
3019 E: u32,
30193020 };
30203021
30213022 var a = Item{ .C = Point{ .x = 1, .y = 2 } };
......@@ -3023,8 +3024,9 @@ test "switch on tagged union" {
30233024 // Switching on more complex enums is allowed.
30243025 const b = switch (a) {
30253026 // A capture group is allowed on a match, and will return the enum
3026 // value matched.
3027 Item.A => |item| item,
3027 // value matched. If the payloads of both cases are the same
3028 // they can be put into the same switch prong.
3029 Item.A, Item.E => |item| item,
30283030
30293031 // A reference to the matched value can be obtained using `*` syntax.
30303032 Item.C => |*item| blk: {
src/ir.cpp+34-4
......@@ -19230,10 +19230,6 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1923019230 assert(enum_type != nullptr);
1923119231 assert(enum_type->id == ZigTypeIdEnum);
1923219232
19233 if (instruction->prongs_len != 1) {
19234 return target_value_ptr;
19235 }
19236
1923719233 IrInstruction *prong_value = instruction->prongs_ptr[0]->child;
1923819234 if (type_is_invalid(prong_value->value.type))
1923919235 return ira->codegen->invalid_instruction;
......@@ -19248,6 +19244,40 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1924819244
1924919245 TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag);
1925019246
19247 if (instruction->prongs_len != 1) {
19248 ErrorMsg *invalid_payload = nullptr;
19249 Buf *invalid_payload_list = nullptr;
19250
19251 for (size_t i = 1; i < instruction->prongs_len; i++) {
19252 IrInstruction *casted_prong_value = ir_implicit_cast(ira, instruction->prongs_ptr[i]->child, enum_type);
19253 if (type_is_invalid(casted_prong_value->value.type))
19254 return ira->codegen->invalid_instruction;
19255
19256 ConstExprValue *next_prong = ir_resolve_const(ira, casted_prong_value, UndefBad);
19257 if (!next_prong)
19258 return ira->codegen->invalid_instruction;
19259
19260 ZigType *payload = find_union_field_by_tag(target_type, &next_prong->data.x_enum_tag)->type_entry;
19261
19262 if (field->type_entry != payload) {
19263 if (!invalid_payload) {
19264 invalid_payload = ir_add_error(ira, &instruction->base,
19265 buf_sprintf("switch prong contains cases with different payloads"));
19266 invalid_payload_list = buf_sprintf("payload types are %s", buf_ptr(&field->type_entry->name));
19267 }
19268
19269 if (i == instruction->prongs_len - 1)
19270 buf_append_buf(invalid_payload_list, buf_sprintf(" and %s", buf_ptr(&payload->name)));
19271 else
19272 buf_append_buf(invalid_payload_list, buf_sprintf(", %s", buf_ptr(&payload->name)));
19273 }
19274 }
19275
19276 if (invalid_payload)
19277 add_error_note(ira->codegen, invalid_payload,
19278 ((IrInstruction*)instruction)->source_node, invalid_payload_list);
19279 }
19280
1925119281 if (instr_is_comptime(target_value_ptr)) {
1925219282 ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad);
1925319283 if (!target_value_ptr)
test/compile_errors.zig+17
......@@ -6073,4 +6073,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
60736073 "tmp.zig:5:30: error: expression value is ignored",
60746074 "tmp.zig:9:30: error: expression value is ignored",
60756075 );
6076
6077 cases.add(
6078 "capture group on switch prong with different payloads",
6079 \\const Union = union(enum) {
6080 \\ A: usize,
6081 \\ B: isize,
6082 \\};
6083 \\comptime {
6084 \\ var u = Union{ .A = 8 };
6085 \\ switch (u) {
6086 \\ .A, .B => |e| unreachable,
6087 \\ }
6088 \\}
6089 ,
6090 "tmp.zig:8:20: error: switch prong contains cases with different payloads",
6091 "tmp.zig:8:20: note: payload types are usize and isize",
6092 );
60766093}
test/stage1/behavior/switch.zig+18
......@@ -391,3 +391,21 @@ test "switch with null and T peer types and inferred result location type" {
391391 S.doTheTest(1);
392392 comptime S.doTheTest(1);
393393}
394
395test "switch prongs with cases with identical payloads" {
396 const Union = union(enum) {
397 A: usize,
398 B: isize,
399 C: usize,
400 };
401 const S = struct {
402 fn doTheTest(u: Union) void {
403 switch (u) {
404 .A, .C => |e| expect(@typeOf(e) == usize),
405 .B => |e| expect(@typeOf(e) == isize),
406 }
407 }
408 };
409 S.doTheTest(Union{ .A = 8 });
410 comptime S.doTheTest(Union{ .B = -8 });
411}