authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-04 00:35:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-04 00:35:47-04:00
logb109155528e19a181b123ef08667a415c5664320
tree35994567d3e9c618e05301131c581d85146d4e78
parentc2cf04086a74a3c0ac31dbc1b8d01de76988c7ae
parent96fd1030730e2980fa852ae45a67a2a4008bb163
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'emekoi-impl-1107'


4 files changed, 102 insertions(+), 19 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 payload types 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+46-17
......@@ -19229,24 +19229,53 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1922919229 ZigType *enum_type = target_type->data.unionation.tag_type;
1923019230 assert(enum_type != nullptr);
1923119231 assert(enum_type->id == ZigTypeIdEnum);
19232 assert(instruction->prongs_len > 0);
1923219233
19233 if (instruction->prongs_len != 1) {
19234 return target_value_ptr;
19235 }
19236
19237 IrInstruction *prong_value = instruction->prongs_ptr[0]->child;
19238 if (type_is_invalid(prong_value->value.type))
19234 IrInstruction *first_prong_value = instruction->prongs_ptr[0]->child;
19235 if (type_is_invalid(first_prong_value->value.type))
1923919236 return ira->codegen->invalid_instruction;
1924019237
19241 IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type);
19242 if (type_is_invalid(casted_prong_value->value.type))
19238 IrInstruction *first_casted_prong_value = ir_implicit_cast(ira, first_prong_value, enum_type);
19239 if (type_is_invalid(first_casted_prong_value->value.type))
1924319240 return ira->codegen->invalid_instruction;
1924419241
19245 ConstExprValue *prong_val = ir_resolve_const(ira, casted_prong_value, UndefBad);
19246 if (!prong_val)
19242 ConstExprValue *first_prong_val = ir_resolve_const(ira, first_casted_prong_value, UndefBad);
19243 if (first_prong_val == nullptr)
1924719244 return ira->codegen->invalid_instruction;
1924819245
19249 TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag);
19246 TypeUnionField *first_field = find_union_field_by_tag(target_type, &first_prong_val->data.x_enum_tag);
19247
19248 ErrorMsg *invalid_payload_msg = nullptr;
19249 for (size_t prong_i = 1; prong_i < instruction->prongs_len; prong_i += 1) {
19250 IrInstruction *this_prong_inst = instruction->prongs_ptr[prong_i]->child;
19251 if (type_is_invalid(this_prong_inst->value.type))
19252 return ira->codegen->invalid_instruction;
19253
19254 IrInstruction *this_casted_prong_value = ir_implicit_cast(ira, this_prong_inst, enum_type);
19255 if (type_is_invalid(this_casted_prong_value->value.type))
19256 return ira->codegen->invalid_instruction;
19257
19258 ConstExprValue *this_prong = ir_resolve_const(ira, this_casted_prong_value, UndefBad);
19259 if (this_prong == nullptr)
19260 return ira->codegen->invalid_instruction;
19261
19262 TypeUnionField *payload_field = find_union_field_by_tag(target_type, &this_prong->data.x_enum_tag);
19263 ZigType *payload_type = payload_field->type_entry;
19264 if (first_field->type_entry != payload_type) {
19265 if (invalid_payload_msg == nullptr) {
19266 invalid_payload_msg = ir_add_error(ira, &instruction->base,
19267 buf_sprintf("capture group with incompatible types"));
19268 add_error_note(ira->codegen, invalid_payload_msg, first_prong_value->source_node,
19269 buf_sprintf("type '%s' here", buf_ptr(&first_field->type_entry->name)));
19270 }
19271 add_error_note(ira->codegen, invalid_payload_msg, this_prong_inst->source_node,
19272 buf_sprintf("type '%s' here", buf_ptr(&payload_field->type_entry->name)));
19273 }
19274 }
19275
19276 if (invalid_payload_msg != nullptr) {
19277 return ira->codegen->invalid_instruction;
19278 }
1925019279
1925119280 if (instr_is_comptime(target_value_ptr)) {
1925219281 ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad);
......@@ -19258,7 +19287,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1925819287 return ira->codegen->invalid_instruction;
1925919288
1926019289 IrInstruction *result = ir_const(ira, &instruction->base,
19261 get_pointer_to_type(ira->codegen, field->type_entry,
19290 get_pointer_to_type(ira->codegen, first_field->type_entry,
1926219291 target_val_ptr->type->data.pointer.is_const));
1926319292 ConstExprValue *out_val = &result->value;
1926419293 out_val->data.x_ptr.special = ConstPtrSpecialRef;
......@@ -19268,8 +19297,8 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
1926819297 }
1926919298
1927019299 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb,
19271 instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false, false);
19272 result->value.type = get_pointer_to_type(ira->codegen, field->type_entry,
19300 instruction->base.scope, instruction->base.source_node, target_value_ptr, first_field, false, false);
19301 result->value.type = get_pointer_to_type(ira->codegen, first_field->type_entry,
1927319302 target_value_ptr->value.type->data.pointer.is_const);
1927419303 return result;
1927519304 } else if (target_type->id == ZigTypeIdErrorSet) {
......@@ -22977,11 +23006,11 @@ static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructi
2297723006 IrInstruction *type_value = instruction->type_value->child;
2297823007 if (type_is_invalid(type_value->value.type))
2297923008 return ira->codegen->invalid_instruction;
22980
23009
2298123010 ZigType *expr_type = ir_resolve_type(ira, type_value);
2298223011 if (type_is_invalid(expr_type))
2298323012 return ira->codegen->invalid_instruction;
22984
23013
2298523014 // Only allow float types, and vectors of floats.
2298623015 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
2298723016 if (float_type->id != ZigTypeIdFloat) {
......@@ -25082,7 +25111,7 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct
2508225111 IrInstruction *type = instruction->type->child;
2508325112 if (type_is_invalid(type->value.type))
2508425113 return ira->codegen->invalid_instruction;
25085
25114
2508625115 ZigType *expr_type = ir_resolve_type(ira, type);
2508725116 if (type_is_invalid(expr_type))
2508825117 return ira->codegen->invalid_instruction;
test/compile_errors.zig+18
......@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "capture group on switch prong with incompatible payload types",
7 \\const Union = union(enum) {
8 \\ A: usize,
9 \\ B: isize,
10 \\};
11 \\comptime {
12 \\ var u = Union{ .A = 8 };
13 \\ switch (u) {
14 \\ .A, .B => |e| unreachable,
15 \\ }
16 \\}
17 ,
18 "tmp.zig:8:20: error: capture group with incompatible types",
19 "tmp.zig:8:9: note: type 'usize' here",
20 "tmp.zig:8:13: note: type 'isize' here",
21 );
22
523 cases.add(
624 "wrong type to @hasField",
725 \\export fn entry() bool {
test/stage1/behavior/switch.zig+34
......@@ -391,3 +391,37 @@ 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 payload types" {
396 const Union = union(enum) {
397 A: usize,
398 B: isize,
399 C: usize,
400 };
401 const S = struct {
402 fn doTheTest() void {
403 doTheSwitch1(Union{ .A = 8 });
404 doTheSwitch2(Union{ .B = -8 });
405 }
406 fn doTheSwitch1(u: Union) void {
407 switch (u) {
408 .A, .C => |e| {
409 expect(@typeOf(e) == usize);
410 expect(e == 8);
411 },
412 .B => |e| @panic("fail"),
413 }
414 }
415 fn doTheSwitch2(u: Union) void {
416 switch (u) {
417 .A, .C => |e| @panic("fail"),
418 .B => |e| {
419 expect(@typeOf(e) == isize);
420 expect(e == -8);
421 },
422 }
423 }
424 };
425 S.doTheTest();
426 comptime S.doTheTest();
427}