| author | |
| committer | |
| log | a3ddd0826bd9c799768c0c707de72c21befa742a |
| tree | 685b621eb041c178af40c0044c74f689d8d6af7b |
| parent | 626b73e8beeaae1cab23f883f877d89d64bbfa39 |
see #10619 files changed, 174 insertions(+), 51 deletions(-)
doc/langref.html.in+27-7| ... | @@ -1900,9 +1900,9 @@ const Value = enum(u2) { | ... | @@ -1900,9 +1900,9 @@ const Value = enum(u2) { |
| 1900 | // Now you can cast between u2 and Value. | 1900 | // Now you can cast between u2 and Value. |
| 1901 | // The ordinal value starts from 0, counting up for each member. | 1901 | // The ordinal value starts from 0, counting up for each member. |
| 1902 | test "enum ordinal value" { | 1902 | test "enum ordinal value" { |
| 1903 | assert(u2(Value.Zero) == 0); | 1903 | assert(@enumToInt(Value.Zero) == 0); |
| 1904 | assert(u2(Value.One) == 1); | 1904 | assert(@enumToInt(Value.One) == 1); |
| 1905 | assert(u2(Value.Two) == 2); | 1905 | assert(@enumToInt(Value.Two) == 2); |
| 1906 | } | 1906 | } |
| 1907 | 1907 | ||
| 1908 | // You can override the ordinal value for an enum. | 1908 | // You can override the ordinal value for an enum. |
| ... | @@ -1912,9 +1912,9 @@ const Value2 = enum(u32) { | ... | @@ -1912,9 +1912,9 @@ const Value2 = enum(u32) { |
| 1912 | Million = 1000000, | 1912 | Million = 1000000, |
| 1913 | }; | 1913 | }; |
| 1914 | test "set enum ordinal value" { | 1914 | test "set enum ordinal value" { |
| 1915 | assert(u32(Value2.Hundred) == 100); | 1915 | assert(@enumToInt(Value2.Hundred) == 100); |
| 1916 | assert(u32(Value2.Thousand) == 1000); | 1916 | assert(@enumToInt(Value2.Thousand) == 1000); |
| 1917 | assert(u32(Value2.Million) == 1000000); | 1917 | assert(@enumToInt(Value2.Million) == 1000000); |
| 1918 | } | 1918 | } |
| 1919 | 1919 | ||
| 1920 | // Enums can have methods, the same as structs and unions. | 1920 | // Enums can have methods, the same as structs and unions. |
| ... | @@ -4931,6 +4931,14 @@ test "main" { | ... | @@ -4931,6 +4931,14 @@ test "main" { |
| 4931 | {#see_also|@import#} | 4931 | {#see_also|@import#} |
| 4932 | {#header_close#} | 4932 | {#header_close#} |
| 4933 | 4933 | ||
| 4934 | {#header_open|@enumToInt#} | ||
| 4935 | <pre><code class="zig">@enumToInt(enum_value: var) var</code></pre> | ||
| 4936 | <p> | ||
| 4937 | Converts an enumeration value into its integer tag type. | ||
| 4938 | </p> | ||
| 4939 | {#see_also|@intToEnum#} | ||
| 4940 | {#header_close#} | ||
| 4941 | |||
| 4934 | {#header_open|@errSetCast#} | 4942 | {#header_open|@errSetCast#} |
| 4935 | <pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre> | 4943 | <pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre> |
| 4936 | <p> | 4944 | <p> |
| ... | @@ -5095,6 +5103,18 @@ fn add(a: i32, b: i32) i32 { return a + b; } | ... | @@ -5095,6 +5103,18 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 5095 | </p> | 5103 | </p> |
| 5096 | {#header_close#} | 5104 | {#header_close#} |
| 5097 | 5105 | ||
| 5106 | {#header_open|@intToEnum#} | ||
| 5107 | <pre><code class="zig">@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType</code></pre> | ||
| 5108 | <p> | ||
| 5109 | Converts an integer into an {#link|enum#} value. | ||
| 5110 | </p> | ||
| 5111 | <p> | ||
| 5112 | Attempting to convert an integer which represents no value in the chosen enum type invokes | ||
| 5113 | safety-checked {#link|Undefined Behavior#}. | ||
| 5114 | </p> | ||
| 5115 | {#see_also|@enumToInt#} | ||
| 5116 | {#header_close#} | ||
| 5117 | |||
| 5098 | {#header_open|@intToError#} | 5118 | {#header_open|@intToError#} |
| 5099 | <pre><code class="zig">@intToError(value: @IntType(false, @sizeOf(error) * 8)) error</code></pre> | 5119 | <pre><code class="zig">@intToError(value: @IntType(false, @sizeOf(error) * 8)) error</code></pre> |
| 5100 | <p> | 5120 | <p> |
| ... | @@ -6867,7 +6887,7 @@ hljs.registerLanguage("zig", function(t) { | ... | @@ -6867,7 +6887,7 @@ hljs.registerLanguage("zig", function(t) { |
| 6867 | a = t.IR + "\\s*\\(", | 6887 | a = t.IR + "\\s*\\(", |
| 6868 | c = { | 6888 | c = { |
| 6869 | keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse", | 6889 | keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse", |
| 6870 | built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError", | 6890 | built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum", |
| 6871 | literal: "true false null undefined" | 6891 | literal: "true false null undefined" |
| 6872 | }, | 6892 | }, |
| 6873 | n = [e, t.CLCM, t.CBCM, s, r]; | 6893 | n = [e, t.CLCM, t.CBCM, s, r]; |
src/all_types.hpp+10| ... | @@ -1378,6 +1378,8 @@ enum BuiltinFnId { | ... | @@ -1378,6 +1378,8 @@ enum BuiltinFnId { |
| 1378 | BuiltinFnIdBoolToInt, | 1378 | BuiltinFnIdBoolToInt, |
| 1379 | BuiltinFnIdErrToInt, | 1379 | BuiltinFnIdErrToInt, |
| 1380 | BuiltinFnIdIntToErr, | 1380 | BuiltinFnIdIntToErr, |
| 1381 | BuiltinFnIdEnumToInt, | ||
| 1382 | BuiltinFnIdIntToEnum, | ||
| 1381 | BuiltinFnIdIntType, | 1383 | BuiltinFnIdIntType, |
| 1382 | BuiltinFnIdSetCold, | 1384 | BuiltinFnIdSetCold, |
| 1383 | BuiltinFnIdSetRuntimeSafety, | 1385 | BuiltinFnIdSetRuntimeSafety, |
| ... | @@ -2092,6 +2094,7 @@ enum IrInstructionId { | ... | @@ -2092,6 +2094,7 @@ enum IrInstructionId { |
| 2092 | IrInstructionIdIntToPtr, | 2094 | IrInstructionIdIntToPtr, |
| 2093 | IrInstructionIdPtrToInt, | 2095 | IrInstructionIdPtrToInt, |
| 2094 | IrInstructionIdIntToEnum, | 2096 | IrInstructionIdIntToEnum, |
| 2097 | IrInstructionIdEnumToInt, | ||
| 2095 | IrInstructionIdIntToErr, | 2098 | IrInstructionIdIntToErr, |
| 2096 | IrInstructionIdErrToInt, | 2099 | IrInstructionIdErrToInt, |
| 2097 | IrInstructionIdCheckSwitchProngs, | 2100 | IrInstructionIdCheckSwitchProngs, |
| ... | @@ -2905,6 +2908,13 @@ struct IrInstructionIntToPtr { | ... | @@ -2905,6 +2908,13 @@ struct IrInstructionIntToPtr { |
| 2905 | struct IrInstructionIntToEnum { | 2908 | struct IrInstructionIntToEnum { |
| 2906 | IrInstruction base; | 2909 | IrInstruction base; |
| 2907 | 2910 | ||
| 2911 | IrInstruction *dest_type; | ||
| 2912 | IrInstruction *target; | ||
| 2913 | }; | ||
| 2914 | |||
| 2915 | struct IrInstructionEnumToInt { | ||
| 2916 | IrInstruction base; | ||
| 2917 | |||
| 2908 | IrInstruction *target; | 2918 | IrInstruction *target; |
| 2909 | }; | 2919 | }; |
| 2910 | 2920 |
src/codegen.cpp+3| ... | @@ -4730,6 +4730,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -4730,6 +4730,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 4730 | case IrInstructionIdErrSetCast: | 4730 | case IrInstructionIdErrSetCast: |
| 4731 | case IrInstructionIdFromBytes: | 4731 | case IrInstructionIdFromBytes: |
| 4732 | case IrInstructionIdToBytes: | 4732 | case IrInstructionIdToBytes: |
| 4733 | case IrInstructionIdEnumToInt: | ||
| 4733 | zig_unreachable(); | 4734 | zig_unreachable(); |
| 4734 | 4735 | ||
| 4735 | case IrInstructionIdReturn: | 4736 | case IrInstructionIdReturn: |
| ... | @@ -6325,6 +6326,8 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -6325,6 +6326,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 6325 | create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1); | 6326 | create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1); |
| 6326 | create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1); | 6327 | create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1); |
| 6327 | create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1); | 6328 | create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1); |
| 6329 | create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1); | ||
| 6330 | create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2); | ||
| 6328 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); | 6331 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); |
| 6329 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); | 6332 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 6330 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int | 6333 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int |
src/ir.cpp+105-13| ... | @@ -600,6 +600,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) { | ... | @@ -600,6 +600,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) { |
| 600 | return IrInstructionIdIntToEnum; | 600 | return IrInstructionIdIntToEnum; |
| 601 | } | 601 | } |
| 602 | 602 | ||
| 603 | static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumToInt *) { | ||
| 604 | return IrInstructionIdEnumToInt; | ||
| 605 | } | ||
| 606 | |||
| 603 | static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) { | 607 | static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) { |
| 604 | return IrInstructionIdIntToErr; | 608 | return IrInstructionIdIntToErr; |
| 605 | } | 609 | } |
| ... | @@ -2378,10 +2382,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2378,10 +2382,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode |
| 2378 | } | 2382 | } |
| 2379 | 2383 | ||
| 2380 | static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2384 | static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2381 | IrInstruction *target) | 2385 | IrInstruction *dest_type, IrInstruction *target) |
| 2382 | { | 2386 | { |
| 2383 | IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>( | 2387 | IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>( |
| 2384 | irb, scope, source_node); | 2388 | irb, scope, source_node); |
| 2389 | instruction->dest_type = dest_type; | ||
| 2390 | instruction->target = target; | ||
| 2391 | |||
| 2392 | if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); | ||
| 2393 | ir_ref_instruction(target, irb->current_basic_block); | ||
| 2394 | |||
| 2395 | return &instruction->base; | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | |||
| 2399 | |||
| 2400 | static IrInstruction *ir_build_enum_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2401 | IrInstruction *target) | ||
| 2402 | { | ||
| 2403 | IrInstructionEnumToInt *instruction = ir_build_instruction<IrInstructionEnumToInt>( | ||
| 2404 | irb, scope, source_node); | ||
| 2385 | instruction->target = target; | 2405 | instruction->target = target; |
| 2386 | 2406 | ||
| 2387 | ir_ref_instruction(target, irb->current_basic_block); | 2407 | ir_ref_instruction(target, irb->current_basic_block); |
| ... | @@ -4708,6 +4728,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4708,6 +4728,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4708 | // this value does not mean anything since we passed non-null values for other arg | 4728 | // this value does not mean anything since we passed non-null values for other arg |
| 4709 | AtomicOrderMonotonic); | 4729 | AtomicOrderMonotonic); |
| 4710 | } | 4730 | } |
| 4731 | case BuiltinFnIdIntToEnum: | ||
| 4732 | { | ||
| 4733 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4734 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4735 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4736 | return arg0_value; | ||
| 4737 | |||
| 4738 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4739 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 4740 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 4741 | return arg1_value; | ||
| 4742 | |||
| 4743 | IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value); | ||
| 4744 | return ir_lval_wrap(irb, scope, result, lval); | ||
| 4745 | } | ||
| 4746 | case BuiltinFnIdEnumToInt: | ||
| 4747 | { | ||
| 4748 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4749 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 4750 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 4751 | return arg0_value; | ||
| 4752 | |||
| 4753 | IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); | ||
| 4754 | return ir_lval_wrap(irb, scope, result, lval); | ||
| 4755 | } | ||
| 4711 | } | 4756 | } |
| 4712 | zig_unreachable(); | 4757 | zig_unreachable(); |
| 4713 | } | 4758 | } |
| ... | @@ -9951,7 +9996,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour | ... | @@ -9951,7 +9996,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 9951 | } | 9996 | } |
| 9952 | 9997 | ||
| 9953 | IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope, | 9998 | IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope, |
| 9954 | source_instr->source_node, target); | 9999 | source_instr->source_node, nullptr, target); |
| 9955 | result->value.type = wanted_type; | 10000 | result->value.type = wanted_type; |
| 9956 | return result; | 10001 | return result; |
| 9957 | } | 10002 | } |
| ... | @@ -10485,16 +10530,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10485,16 +10530,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10485 | return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); | 10530 | return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type); |
| 10486 | } | 10531 | } |
| 10487 | 10532 | ||
| 10488 | // explicit cast from integer to enum type with no payload | ||
| 10489 | if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) { | ||
| 10490 | return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type); | ||
| 10491 | } | ||
| 10492 | |||
| 10493 | // explicit cast from enum type with no payload to integer | ||
| 10494 | if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) { | ||
| 10495 | return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type); | ||
| 10496 | } | ||
| 10497 | |||
| 10498 | // explicit cast from union to the enum type of the union | 10533 | // explicit cast from union to the enum type of the union |
| 10499 | if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { | 10534 | if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { |
| 10500 | type_ensure_zero_bits_known(ira->codegen, actual_type); | 10535 | type_ensure_zero_bits_known(ira->codegen, actual_type); |
| ... | @@ -20262,11 +20297,63 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction | ... | @@ -20262,11 +20297,63 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction |
| 20262 | return result->value.type; | 20297 | return result->value.type; |
| 20263 | } | 20298 | } |
| 20264 | 20299 | ||
| 20300 | static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { | ||
| 20301 | IrInstruction *target = instruction->target->other; | ||
| 20302 | if (type_is_invalid(target->value.type)) | ||
| 20303 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20304 | |||
| 20305 | if (target->value.type->id != TypeTableEntryIdEnum) { | ||
| 20306 | ir_add_error(ira, instruction->target, | ||
| 20307 | buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); | ||
| 20308 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20309 | } | ||
| 20310 | |||
| 20311 | type_ensure_zero_bits_known(ira->codegen, target->value.type); | ||
| 20312 | if (type_is_invalid(target->value.type)) | ||
| 20313 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20314 | |||
| 20315 | TypeTableEntry *tag_type = target->value.type->data.enumeration.tag_int_type; | ||
| 20316 | |||
| 20317 | IrInstruction *result = ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type); | ||
| 20318 | ir_link_new_instruction(result, &instruction->base); | ||
| 20319 | return result->value.type; | ||
| 20320 | } | ||
| 20321 | |||
| 20322 | static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { | ||
| 20323 | IrInstruction *dest_type_value = instruction->dest_type->other; | ||
| 20324 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); | ||
| 20325 | if (type_is_invalid(dest_type)) | ||
| 20326 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20327 | |||
| 20328 | if (dest_type->id != TypeTableEntryIdEnum) { | ||
| 20329 | ir_add_error(ira, instruction->dest_type, | ||
| 20330 | buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name))); | ||
| 20331 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20332 | } | ||
| 20333 | |||
| 20334 | type_ensure_zero_bits_known(ira->codegen, dest_type); | ||
| 20335 | if (type_is_invalid(dest_type)) | ||
| 20336 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20337 | |||
| 20338 | TypeTableEntry *tag_type = dest_type->data.enumeration.tag_int_type; | ||
| 20339 | |||
| 20340 | IrInstruction *target = instruction->target->other; | ||
| 20341 | if (type_is_invalid(target->value.type)) | ||
| 20342 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20343 | |||
| 20344 | IrInstruction *casted_target = ir_implicit_cast(ira, target, tag_type); | ||
| 20345 | if (type_is_invalid(casted_target->value.type)) | ||
| 20346 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20347 | |||
| 20348 | IrInstruction *result = ir_analyze_int_to_enum(ira, &instruction->base, casted_target, dest_type); | ||
| 20349 | ir_link_new_instruction(result, &instruction->base); | ||
| 20350 | return result->value.type; | ||
| 20351 | } | ||
| 20352 | |||
| 20265 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 20353 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 20266 | switch (instruction->id) { | 20354 | switch (instruction->id) { |
| 20267 | case IrInstructionIdInvalid: | 20355 | case IrInstructionIdInvalid: |
| 20268 | case IrInstructionIdWidenOrShorten: | 20356 | case IrInstructionIdWidenOrShorten: |
| 20269 | case IrInstructionIdIntToEnum: | ||
| 20270 | case IrInstructionIdStructInit: | 20357 | case IrInstructionIdStructInit: |
| 20271 | case IrInstructionIdUnionInit: | 20358 | case IrInstructionIdUnionInit: |
| 20272 | case IrInstructionIdStructFieldPtr: | 20359 | case IrInstructionIdStructFieldPtr: |
| ... | @@ -20531,6 +20618,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -20531,6 +20618,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 20531 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); | 20618 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); |
| 20532 | case IrInstructionIdErrToInt: | 20619 | case IrInstructionIdErrToInt: |
| 20533 | return ir_analyze_instruction_err_to_int(ira, (IrInstructionErrToInt *)instruction); | 20620 | return ir_analyze_instruction_err_to_int(ira, (IrInstructionErrToInt *)instruction); |
| 20621 | case IrInstructionIdIntToEnum: | ||
| 20622 | return ir_analyze_instruction_int_to_enum(ira, (IrInstructionIntToEnum *)instruction); | ||
| 20623 | case IrInstructionIdEnumToInt: | ||
| 20624 | return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction); | ||
| 20534 | } | 20625 | } |
| 20535 | zig_unreachable(); | 20626 | zig_unreachable(); |
| 20536 | } | 20627 | } |
| ... | @@ -20754,6 +20845,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -20754,6 +20845,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 20754 | case IrInstructionIdBoolToInt: | 20845 | case IrInstructionIdBoolToInt: |
| 20755 | case IrInstructionIdFromBytes: | 20846 | case IrInstructionIdFromBytes: |
| 20756 | case IrInstructionIdToBytes: | 20847 | case IrInstructionIdToBytes: |
| 20848 | case IrInstructionIdEnumToInt: | ||
| 20757 | return false; | 20849 | return false; |
| 20758 | 20850 | ||
| 20759 | case IrInstructionIdAsm: | 20851 | case IrInstructionIdAsm: |
src/ir_print.cpp+14| ... | @@ -928,6 +928,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction | ... | @@ -928,6 +928,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction |
| 928 | 928 | ||
| 929 | static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) { | 929 | static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) { |
| 930 | fprintf(irp->f, "@intToEnum("); | 930 | fprintf(irp->f, "@intToEnum("); |
| 931 | if (instruction->dest_type == nullptr) { | ||
| 932 | fprintf(irp->f, "(null)"); | ||
| 933 | } else { | ||
| 934 | ir_print_other_instruction(irp, instruction->dest_type); | ||
| 935 | } | ||
| 936 | ir_print_other_instruction(irp, instruction->target); | ||
| 937 | fprintf(irp->f, ")"); | ||
| 938 | } | ||
| 939 | |||
| 940 | static void ir_print_enum_to_int(IrPrint *irp, IrInstructionEnumToInt *instruction) { | ||
| 941 | fprintf(irp->f, "@enumToInt("); | ||
| 931 | ir_print_other_instruction(irp, instruction->target); | 942 | ir_print_other_instruction(irp, instruction->target); |
| 932 | fprintf(irp->f, ")"); | 943 | fprintf(irp->f, ")"); |
| 933 | } | 944 | } |
| ... | @@ -1717,6 +1728,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1717,6 +1728,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1717 | case IrInstructionIdAtomicLoad: | 1728 | case IrInstructionIdAtomicLoad: |
| 1718 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); | 1729 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); |
| 1719 | break; | 1730 | break; |
| 1731 | case IrInstructionIdEnumToInt: | ||
| 1732 | ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction); | ||
| 1733 | break; | ||
| 1720 | } | 1734 | } |
| 1721 | fprintf(irp->f, "\n"); | 1735 | fprintf(irp->f, "\n"); |
| 1722 | } | 1736 | } |
std/json.zig+1-1| ... | @@ -180,7 +180,7 @@ pub const StreamingParser = struct { | ... | @@ -180,7 +180,7 @@ pub const StreamingParser = struct { |
| 180 | pub fn fromInt(x: var) State { | 180 | pub fn fromInt(x: var) State { |
| 181 | debug.assert(x == 0 or x == 1); | 181 | debug.assert(x == 0 or x == 1); |
| 182 | const T = @TagType(State); | 182 | const T = @TagType(State); |
| 183 | return State(@intCast(T, x)); | 183 | return @intToEnum(State, @intCast(T, x)); |
| 184 | } | 184 | } |
| 185 | }; | 185 | }; |
| 186 | 186 |
test/cases/enum.zig+8-8| ... | @@ -92,14 +92,14 @@ test "enum to int" { | ... | @@ -92,14 +92,14 @@ test "enum to int" { |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | fn shouldEqual(n: Number, expected: u3) void { | 94 | fn shouldEqual(n: Number, expected: u3) void { |
| 95 | assert(u3(n) == expected); | 95 | assert(@enumToInt(n) == expected); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | test "int to enum" { | 98 | test "int to enum" { |
| 99 | testIntToEnumEval(3); | 99 | testIntToEnumEval(3); |
| 100 | } | 100 | } |
| 101 | fn testIntToEnumEval(x: i32) void { | 101 | fn testIntToEnumEval(x: i32) void { |
| 102 | assert(IntToEnumNumber(@intCast(u3, x)) == IntToEnumNumber.Three); | 102 | assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three); |
| 103 | } | 103 | } |
| 104 | const IntToEnumNumber = enum { | 104 | const IntToEnumNumber = enum { |
| 105 | Zero, | 105 | Zero, |
| ... | @@ -768,7 +768,7 @@ test "casting enum to its tag type" { | ... | @@ -768,7 +768,7 @@ test "casting enum to its tag type" { |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | fn testCastEnumToTagType(value: Small2) void { | 770 | fn testCastEnumToTagType(value: Small2) void { |
| 771 | assert(u2(value) == 1); | 771 | assert(@enumToInt(value) == 1); |
| 772 | } | 772 | } |
| 773 | 773 | ||
| 774 | const MultipleChoice = enum(u32) { | 774 | const MultipleChoice = enum(u32) { |
| ... | @@ -784,7 +784,7 @@ test "enum with specified tag values" { | ... | @@ -784,7 +784,7 @@ test "enum with specified tag values" { |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { | 786 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void { |
| 787 | assert(u32(x) == 60); | 787 | assert(@enumToInt(x) == 60); |
| 788 | assert(1234 == switch (x) { | 788 | assert(1234 == switch (x) { |
| 789 | MultipleChoice.A => 1, | 789 | MultipleChoice.A => 1, |
| 790 | MultipleChoice.B => 2, | 790 | MultipleChoice.B => 2, |
| ... | @@ -811,7 +811,7 @@ test "enum with specified and unspecified tag values" { | ... | @@ -811,7 +811,7 @@ test "enum with specified and unspecified tag values" { |
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | 813 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { |
| 814 | assert(u32(x) == 1000); | 814 | assert(@enumToInt(x) == 1000); |
| 815 | assert(1234 == switch (x) { | 815 | assert(1234 == switch (x) { |
| 816 | MultipleChoice2.A => 1, | 816 | MultipleChoice2.A => 1, |
| 817 | MultipleChoice2.B => 2, | 817 | MultipleChoice2.B => 2, |
| ... | @@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { | ... | @@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { |
| 826 | } | 826 | } |
| 827 | 827 | ||
| 828 | test "cast integer literal to enum" { | 828 | test "cast integer literal to enum" { |
| 829 | assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1); | 829 | assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1); |
| 830 | assert(MultipleChoice2(40) == MultipleChoice2.B); | 830 | assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B); |
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | const EnumWithOneMember = enum { | 833 | const EnumWithOneMember = enum { |
| ... | @@ -865,7 +865,7 @@ const EnumWithTagValues = enum(u4) { | ... | @@ -865,7 +865,7 @@ const EnumWithTagValues = enum(u4) { |
| 865 | D = 1 << 3, | 865 | D = 1 << 3, |
| 866 | }; | 866 | }; |
| 867 | test "enum with tag values don't require parens" { | 867 | test "enum with tag values don't require parens" { |
| 868 | assert(u4(EnumWithTagValues.C) == 0b0100); | 868 | assert(@enumToInt(EnumWithTagValues.C) == 0b0100); |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | test "enum with 1 field but explicit tag type should still have the tag type" { | 871 | test "enum with 1 field but explicit tag type should still have the tag type" { |
test/cases/union.zig+2-2| ... | @@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) { | ... | @@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) { |
| 126 | test "simple union(enum(u32))" { | 126 | test "simple union(enum(u32))" { |
| 127 | var x = MultipleChoice.C; | 127 | var x = MultipleChoice.C; |
| 128 | assert(x == MultipleChoice.C); | 128 | assert(x == MultipleChoice.C); |
| 129 | assert(u32(@TagType(MultipleChoice)(x)) == 60); | 129 | assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | const MultipleChoice2 = union(enum(u32)) { | 132 | const MultipleChoice2 = union(enum(u32)) { |
| ... | @@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" { | ... | @@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" { |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void { | 150 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void { |
| 151 | assert(u32(@TagType(MultipleChoice2)(x.*)) == 60); | 151 | assert(@enumToInt(@TagType(MultipleChoice2)(x.*)) == 60); |
| 152 | assert(1123 == switch (x.*) { | 152 | assert(1123 == switch (x.*) { |
| 153 | MultipleChoice2.A => 1, | 153 | MultipleChoice2.A => 1, |
| 154 | MultipleChoice2.B => 2, | 154 | MultipleChoice2.B => 2, |
test/compile_errors.zig+4-20| ... | @@ -3709,22 +3709,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3709,22 +3709,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3709 | ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'", | 3709 | ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'", |
| 3710 | ); | 3710 | ); |
| 3711 | 3711 | ||
| 3712 | cases.add( | ||
| 3713 | "explicitly casting enum to non tag type", | ||
| 3714 | \\const Small = enum(u2) { | ||
| 3715 | \\ One, | ||
| 3716 | \\ Two, | ||
| 3717 | \\ Three, | ||
| 3718 | \\ Four, | ||
| 3719 | \\}; | ||
| 3720 | \\ | ||
| 3721 | \\export fn entry() void { | ||
| 3722 | \\ var x = u3(Small.Two); | ||
| 3723 | \\} | ||
| 3724 | , | ||
| 3725 | ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'", | ||
| 3726 | ); | ||
| 3727 | |||
| 3728 | cases.add( | 3712 | cases.add( |
| 3729 | "explicitly casting non tag type to enum", | 3713 | "explicitly casting non tag type to enum", |
| 3730 | \\const Small = enum(u2) { | 3714 | \\const Small = enum(u2) { |
| ... | @@ -3736,10 +3720,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3736,10 +3720,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3736 | \\ | 3720 | \\ |
| 3737 | \\export fn entry() void { | 3721 | \\export fn entry() void { |
| 3738 | \\ var y = u3(3); | 3722 | \\ var y = u3(3); |
| 3739 | \\ var x = Small(y); | 3723 | \\ var x = @intToEnum(Small, y); |
| 3740 | \\} | 3724 | \\} |
| 3741 | , | 3725 | , |
| 3742 | ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'", | 3726 | ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'", |
| 3743 | ); | 3727 | ); |
| 3744 | 3728 | ||
| 3745 | cases.add( | 3729 | cases.add( |
| ... | @@ -4020,10 +4004,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4020,10 +4004,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4020 | \\ B = 11, | 4004 | \\ B = 11, |
| 4021 | \\}; | 4005 | \\}; |
| 4022 | \\export fn entry() void { | 4006 | \\export fn entry() void { |
| 4023 | \\ var x = Foo(0); | 4007 | \\ var x = @intToEnum(Foo, 0); |
| 4024 | \\} | 4008 | \\} |
| 4025 | , | 4009 | , |
| 4026 | ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", | 4010 | ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0", |
| 4027 | ".tmp_source.zig:1:13: note: 'Foo' declared here", | 4011 | ".tmp_source.zig:1:13: note: 'Foo' declared here", |
| 4028 | ); | 4012 | ); |
| 4029 | 4013 |