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

improve the error message and test coverage


4 files changed, 79 insertions(+), 63 deletions(-)

doc/langref.html.in+1-1
...@@ -3024,7 +3024,7 @@ test "switch on tagged union" {...@@ -3024,7 +3024,7 @@ test "switch on tagged union" {
3024 // Switching on more complex enums is allowed.3024 // Switching on more complex enums is allowed.
3025 const b = switch (a) {3025 const b = switch (a) {
3026 // A capture group is allowed on a match, and will return the enum3026 // A capture group is allowed on a match, and will return the enum
3027 // value matched. If the payloads of both cases are the same3027 // value matched. If the payload types of both cases are the same
3028 // they can be put into the same switch prong.3028 // they can be put into the same switch prong.
3029 Item.A, Item.E => |item| item,3029 Item.A, Item.E => |item| item,
30303030
src/ir.cpp+38-39
...@@ -19229,53 +19229,52 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru...@@ -19229,53 +19229,52 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
19229 ZigType *enum_type = target_type->data.unionation.tag_type;19229 ZigType *enum_type = target_type->data.unionation.tag_type;
19230 assert(enum_type != nullptr);19230 assert(enum_type != nullptr);
19231 assert(enum_type->id == ZigTypeIdEnum);19231 assert(enum_type->id == ZigTypeIdEnum);
19232 assert(instruction->prongs_len > 0);
1923219233
19233 IrInstruction *prong_value = instruction->prongs_ptr[0]->child;19234 IrInstruction *first_prong_value = instruction->prongs_ptr[0]->child;
19234 if (type_is_invalid(prong_value->value.type))19235 if (type_is_invalid(first_prong_value->value.type))
19235 return ira->codegen->invalid_instruction;19236 return ira->codegen->invalid_instruction;
1923619237
19237 IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type);19238 IrInstruction *first_casted_prong_value = ir_implicit_cast(ira, first_prong_value, enum_type);
19238 if (type_is_invalid(casted_prong_value->value.type))19239 if (type_is_invalid(first_casted_prong_value->value.type))
19239 return ira->codegen->invalid_instruction;19240 return ira->codegen->invalid_instruction;
1924019241
19241 ConstExprValue *prong_val = ir_resolve_const(ira, casted_prong_value, UndefBad);19242 ConstExprValue *first_prong_val = ir_resolve_const(ira, first_casted_prong_value, UndefBad);
19242 if (!prong_val)19243 if (first_prong_val == nullptr)
19243 return ira->codegen->invalid_instruction;19244 return ira->codegen->invalid_instruction;
1924419245
19245 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);
1924619247
19247 if (instruction->prongs_len != 1) {19248 ErrorMsg *invalid_payload_msg = nullptr;
19248 ErrorMsg *invalid_payload = nullptr;19249 for (size_t prong_i = 1; prong_i < instruction->prongs_len; prong_i += 1) {
19249 Buf *invalid_payload_list = nullptr;19250 IrInstruction *this_prong_inst = instruction->prongs_ptr[prong_i]->child;
1925019251 if (type_is_invalid(this_prong_inst->value.type))
19251 for (size_t i = 1; i < instruction->prongs_len; i++) {19252 return ira->codegen->invalid_instruction;
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;
1925919253
19260 ZigType *payload = find_union_field_by_tag(target_type, &next_prong->data.x_enum_tag)->type_entry;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;
1926119257
19262 if (field->type_entry != payload) {19258 ConstExprValue *this_prong = ir_resolve_const(ira, this_casted_prong_value, UndefBad);
19263 if (!invalid_payload) {19259 if (this_prong == nullptr)
19264 invalid_payload = ir_add_error(ira, &instruction->base,19260 return ira->codegen->invalid_instruction;
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 }
1926819261
19269 if (i == instruction->prongs_len - 1)19262 TypeUnionField *payload_field = find_union_field_by_tag(target_type, &this_prong->data.x_enum_tag);
19270 buf_append_buf(invalid_payload_list, buf_sprintf(" and %s", buf_ptr(&payload->name)));19263 ZigType *payload_type = payload_field->type_entry;
19271 else19264 if (first_field->type_entry != payload_type) {
19272 buf_append_buf(invalid_payload_list, buf_sprintf(", %s", buf_ptr(&payload->name)));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)));
19273 }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)));
19274 }19273 }
19274 }
1927519275
19276 if (invalid_payload)19276 if (invalid_payload_msg != nullptr) {
19277 add_error_note(ira->codegen, invalid_payload,19277 return ira->codegen->invalid_instruction;
19278 ((IrInstruction*)instruction)->source_node, invalid_payload_list);
19279 }19278 }
1928019279
19281 if (instr_is_comptime(target_value_ptr)) {19280 if (instr_is_comptime(target_value_ptr)) {
...@@ -19288,7 +19287,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru...@@ -19288,7 +19287,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
19288 return ira->codegen->invalid_instruction;19287 return ira->codegen->invalid_instruction;
1928919288
19290 IrInstruction *result = ir_const(ira, &instruction->base,19289 IrInstruction *result = ir_const(ira, &instruction->base,
19291 get_pointer_to_type(ira->codegen, field->type_entry,19290 get_pointer_to_type(ira->codegen, first_field->type_entry,
19292 target_val_ptr->type->data.pointer.is_const));19291 target_val_ptr->type->data.pointer.is_const));
19293 ConstExprValue *out_val = &result->value;19292 ConstExprValue *out_val = &result->value;
19294 out_val->data.x_ptr.special = ConstPtrSpecialRef;19293 out_val->data.x_ptr.special = ConstPtrSpecialRef;
...@@ -19298,8 +19297,8 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru...@@ -19298,8 +19297,8 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
19298 }19297 }
1929919298
19300 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb,19299 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb,
19301 instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false, false);19300 instruction->base.scope, instruction->base.source_node, target_value_ptr, first_field, false, false);
19302 result->value.type = get_pointer_to_type(ira->codegen, field->type_entry,19301 result->value.type = get_pointer_to_type(ira->codegen, first_field->type_entry,
19303 target_value_ptr->value.type->data.pointer.is_const);19302 target_value_ptr->value.type->data.pointer.is_const);
19304 return result;19303 return result;
19305 } else if (target_type->id == ZigTypeIdErrorSet) {19304 } else if (target_type->id == ZigTypeIdErrorSet) {
...@@ -23007,11 +23006,11 @@ static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructi...@@ -23007,11 +23006,11 @@ static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructi
23007 IrInstruction *type_value = instruction->type_value->child;23006 IrInstruction *type_value = instruction->type_value->child;
23008 if (type_is_invalid(type_value->value.type))23007 if (type_is_invalid(type_value->value.type))
23009 return ira->codegen->invalid_instruction;23008 return ira->codegen->invalid_instruction;
23010 23009
23011 ZigType *expr_type = ir_resolve_type(ira, type_value);23010 ZigType *expr_type = ir_resolve_type(ira, type_value);
23012 if (type_is_invalid(expr_type))23011 if (type_is_invalid(expr_type))
23013 return ira->codegen->invalid_instruction;23012 return ira->codegen->invalid_instruction;
23014 23013
23015 // Only allow float types, and vectors of floats.23014 // Only allow float types, and vectors of floats.
23016 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;23015 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
23017 if (float_type->id != ZigTypeIdFloat) {23016 if (float_type->id != ZigTypeIdFloat) {
...@@ -25112,7 +25111,7 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct...@@ -25112,7 +25111,7 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct
25112 IrInstruction *type = instruction->type->child;25111 IrInstruction *type = instruction->type->child;
25113 if (type_is_invalid(type->value.type))25112 if (type_is_invalid(type->value.type))
25114 return ira->codegen->invalid_instruction;25113 return ira->codegen->invalid_instruction;
25115 25114
25116 ZigType *expr_type = ir_resolve_type(ira, type);25115 ZigType *expr_type = ir_resolve_type(ira, type);
25117 if (type_is_invalid(expr_type))25116 if (type_is_invalid(expr_type))
25118 return ira->codegen->invalid_instruction;25117 return ira->codegen->invalid_instruction;
test/compile_errors.zig+18-17
...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub 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
5 cases.add(23 cases.add(
6 "wrong type to @hasField",24 "wrong type to @hasField",
7 \\export fn entry() bool {25 \\export fn entry() bool {
...@@ -6073,21 +6091,4 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -6073,21 +6091,4 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
6073 "tmp.zig:5:30: error: expression value is ignored",6091 "tmp.zig:5:30: error: expression value is ignored",
6074 "tmp.zig:9:30: error: expression value is ignored",6092 "tmp.zig:9:30: error: expression value is ignored",
6075 );6093 );
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 );
6093}6094}
test/stage1/behavior/switch.zig+22-6
...@@ -392,20 +392,36 @@ test "switch with null and T peer types and inferred result location type" {...@@ -392,20 +392,36 @@ test "switch with null and T peer types and inferred result location type" {
392 comptime S.doTheTest(1);392 comptime S.doTheTest(1);
393}393}
394394
395test "switch prongs with cases with identical payloads" {395test "switch prongs with cases with identical payload types" {
396 const Union = union(enum) {396 const Union = union(enum) {
397 A: usize,397 A: usize,
398 B: isize,398 B: isize,
399 C: usize,399 C: usize,
400 };400 };
401 const S = struct {401 const S = struct {
402 fn doTheTest(u: Union) void {402 fn doTheTest() void {
403 doTheSwitch1(Union{ .A = 8 });
404 doTheSwitch2(Union{ .B = -8 });
405 }
406 fn doTheSwitch1(u: Union) void {
403 switch (u) {407 switch (u) {
404 .A, .C => |e| expect(@typeOf(e) == usize),408 .A, .C => |e| {
405 .B => |e| expect(@typeOf(e) == isize),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 },
406 }422 }
407 }423 }
408 };424 };
409 S.doTheTest(Union{ .A = 8 });425 S.doTheTest();
410 comptime S.doTheTest(Union{ .B = -8 });426 comptime S.doTheTest();
411}427}