authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-02 17:12:37-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-02 17:12:37-05:00
log98237f7c0ba62099e85a8caf8fc09039845b224e
tree4f0ecbc220a178747c330d457cc1388100bbed43
parent54a0db0daf8fd5ef307f275275e10f32ebd7d27a

casting between integer and enum only works via tag type

See #305

4 files changed, 94 insertions(+), 5 deletions(-)

src/analyze.cpp+4
...@@ -1399,6 +1399,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1399,6 +1399,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1399 enum_type->data.enumeration.is_invalid = true;1399 enum_type->data.enumeration.is_invalid = true;
1400 add_node_error(g, decl_node->data.container_decl.init_arg_expr,1400 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
1401 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));1401 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
1402 } else if (wanted_tag_int_type->data.integral.is_signed) {
1403 enum_type->data.enumeration.is_invalid = true;
1404 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
1405 buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
1402 } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {1406 } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
1403 enum_type->data.enumeration.is_invalid = true;1407 enum_type->data.enumeration.is_invalid = true;
1404 add_node_error(g, decl_node->data.container_decl.init_arg_expr,1408 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
src/ir.cpp+22-2
...@@ -8911,7 +8911,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8911,7 +8911,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8911 wanted_type->id == TypeTableEntryIdEnum &&8911 wanted_type->id == TypeTableEntryIdEnum &&
8912 wanted_type->data.enumeration.gen_field_count == 0)8912 wanted_type->data.enumeration.gen_field_count == 0)
8913 {8913 {
8914 return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);8914 ensure_complete_type(ira->codegen, wanted_type);
8915 if (type_is_invalid(wanted_type))
8916 return ira->codegen->invalid_instruction;
8917 if (actual_type == wanted_type->data.enumeration.tag_type->data.enum_tag.int_type) {
8918 return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
8919 }
8920 ir_add_error(ira, source_instr,
8921 buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
8922 buf_ptr(&actual_type->name),
8923 buf_ptr(&wanted_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
8924 return ira->codegen->invalid_instruction;
8915 }8925 }
89168926
8917 // explicit cast from enum type with no payload to integer8927 // explicit cast from enum type with no payload to integer
...@@ -8919,7 +8929,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8919,7 +8929,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8919 actual_type->id == TypeTableEntryIdEnum &&8929 actual_type->id == TypeTableEntryIdEnum &&
8920 actual_type->data.enumeration.gen_field_count == 0)8930 actual_type->data.enumeration.gen_field_count == 0)
8921 {8931 {
8922 return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);8932 ensure_complete_type(ira->codegen, actual_type);
8933 if (type_is_invalid(actual_type))
8934 return ira->codegen->invalid_instruction;
8935 if (wanted_type == actual_type->data.enumeration.tag_type->data.enum_tag.int_type) {
8936 return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
8937 }
8938 ir_add_error(ira, source_instr,
8939 buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
8940 buf_ptr(&wanted_type->name),
8941 buf_ptr(&actual_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
8942 return ira->codegen->invalid_instruction;
8923 }8943 }
89248944
8925 // explicit cast from undefined to anything8945 // explicit cast from undefined to anything
test/cases/enum.zig+11-3
...@@ -89,8 +89,8 @@ test "enum to int" {...@@ -89,8 +89,8 @@ test "enum to int" {
89 shouldEqual(Number.Four, 4);89 shouldEqual(Number.Four, 4);
90}90}
9191
92fn shouldEqual(n: Number, expected: usize) {92fn shouldEqual(n: Number, expected: u3) {
93 assert(usize(n) == expected);93 assert(u3(n) == expected);
94}94}
9595
9696
...@@ -98,7 +98,7 @@ test "int to enum" {...@@ -98,7 +98,7 @@ test "int to enum" {
98 testIntToEnumEval(3);98 testIntToEnumEval(3);
99}99}
100fn testIntToEnumEval(x: i32) {100fn testIntToEnumEval(x: i32) {
101 assert(IntToEnumNumber(x) == IntToEnumNumber.Three);101 assert(IntToEnumNumber(u3(x)) == IntToEnumNumber.Three);
102}102}
103const IntToEnumNumber = enum {103const IntToEnumNumber = enum {
104 Zero,104 Zero,
...@@ -284,3 +284,11 @@ fn getC(data: &const BitFieldOfEnums) -> C {...@@ -284,3 +284,11 @@ fn getC(data: &const BitFieldOfEnums) -> C {
284 return data.c;284 return data.c;
285}285}
286286
287test "casting enum to its tag type" {
288 testCastEnumToTagType(Small2.Two);
289 comptime testCastEnumToTagType(Small2.Two);
290}
291
292fn testCastEnumToTagType(value: Small2) {
293 assert(u2(value) == 1);
294}
test/compile_errors.zig+57
...@@ -2390,4 +2390,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -2390,4 +2390,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2390 \\}2390 \\}
2391 ,2391 ,
2392 ".tmp_source.zig:1:20: error: expected integer, found 'f32'");2392 ".tmp_source.zig:1:20: error: expected integer, found 'f32'");
2393
2394 cases.add("implicitly casting enum to tag type",
2395 \\const Small = enum(u2) {
2396 \\ One,
2397 \\ Two,
2398 \\ Three,
2399 \\ Four,
2400 \\};
2401 \\
2402 \\export fn entry() {
2403 \\ var x: u2 = Small.Two;
2404 \\}
2405 ,
2406 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'");
2407
2408 cases.add("explicitly casting enum to non tag type",
2409 \\const Small = enum(u2) {
2410 \\ One,
2411 \\ Two,
2412 \\ Three,
2413 \\ Four,
2414 \\};
2415 \\
2416 \\export fn entry() {
2417 \\ var x = u3(Small.Two);
2418 \\}
2419 ,
2420 ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'");
2421
2422 cases.add("explicitly casting non tag type to enum",
2423 \\const Small = enum(u2) {
2424 \\ One,
2425 \\ Two,
2426 \\ Three,
2427 \\ Four,
2428 \\};
2429 \\
2430 \\export fn entry() {
2431 \\ var y = u3(3);
2432 \\ var x = Small(y);
2433 \\}
2434 ,
2435 ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'");
2436
2437 cases.add("non unsigned integer enum tag type",
2438 \\const Small = enum(i2) {
2439 \\ One,
2440 \\ Two,
2441 \\ Three,
2442 \\ Four,
2443 \\};
2444 \\
2445 \\export fn entry() {
2446 \\ var y = Small.Two;
2447 \\}
2448 ,
2449 ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
2393}2450}