| author | |
| committer | |
| log | 66a83d87383cd8de62898171b6665cb1d70af231 |
| tree | ff09db18060a350166cd07a9fb039b43d1a63e37 |
| parent | c8a7ab7eff0f261c47926cf0637e919d42e41940 |
6 files changed, 93 insertions(+), 33 deletions(-)
src/all_types.hpp+7-1| ... | @@ -437,7 +437,6 @@ enum CastOp { | ... | @@ -437,7 +437,6 @@ enum CastOp { |
| 437 | CastOpFloatToInt, | 437 | CastOpFloatToInt, |
| 438 | CastOpBoolToInt, | 438 | CastOpBoolToInt, |
| 439 | CastOpResizeSlice, | 439 | CastOpResizeSlice, |
| 440 | CastOpIntToEnum, | ||
| 441 | CastOpBytesToSlice, | 440 | CastOpBytesToSlice, |
| 442 | }; | 441 | }; |
| 443 | 442 | ||
| ... | @@ -1458,6 +1457,7 @@ enum IrInstructionId { | ... | @@ -1458,6 +1457,7 @@ enum IrInstructionId { |
| 1458 | IrInstructionIdWidenOrShorten, | 1457 | IrInstructionIdWidenOrShorten, |
| 1459 | IrInstructionIdIntToPtr, | 1458 | IrInstructionIdIntToPtr, |
| 1460 | IrInstructionIdPtrToInt, | 1459 | IrInstructionIdPtrToInt, |
| 1460 | IrInstructionIdIntToEnum, | ||
| 1461 | }; | 1461 | }; |
| 1462 | 1462 | ||
| 1463 | struct IrInstruction { | 1463 | struct IrInstruction { |
| ... | @@ -2118,6 +2118,12 @@ struct IrInstructionIntToPtr { | ... | @@ -2118,6 +2118,12 @@ struct IrInstructionIntToPtr { |
| 2118 | IrInstruction *target; | 2118 | IrInstruction *target; |
| 2119 | }; | 2119 | }; |
| 2120 | 2120 | ||
| 2121 | struct IrInstructionIntToEnum { | ||
| 2122 | IrInstruction base; | ||
| 2123 | |||
| 2124 | IrInstruction *target; | ||
| 2125 | }; | ||
| 2126 | |||
| 2121 | enum LValPurpose { | 2127 | enum LValPurpose { |
| 2122 | LValPurposeNone, | 2128 | LValPurposeNone, |
| 2123 | LValPurposeAssign, | 2129 | LValPurposeAssign, |
src/codegen.cpp+20-4| ... | @@ -1075,10 +1075,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, | ... | @@ -1075,10 +1075,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 1075 | assert(wanted_type->id == TypeTableEntryIdInt); | 1075 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 1076 | assert(actual_type->id == TypeTableEntryIdBool); | 1076 | assert(actual_type->id == TypeTableEntryIdBool); |
| 1077 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); | 1077 | return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); |
| 1078 | |||
| 1079 | case CastOpIntToEnum: | ||
| 1080 | return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base), | ||
| 1081 | actual_type, wanted_type->data.enumeration.tag_type, expr_val); | ||
| 1082 | } | 1078 | } |
| 1083 | zig_unreachable(); | 1079 | zig_unreachable(); |
| 1084 | } | 1080 | } |
| ... | @@ -1122,6 +1118,24 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I | ... | @@ -1122,6 +1118,24 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I |
| 1122 | return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, ""); | 1118 | return LLVMBuildPtrToInt(g->builder, target_val, wanted_type->type_ref, ""); |
| 1123 | } | 1119 | } |
| 1124 | 1120 | ||
| 1121 | static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) { | ||
| 1122 | TypeTableEntry *wanted_type = instruction->base.value.type; | ||
| 1123 | assert(wanted_type->id == TypeTableEntryIdEnum); | ||
| 1124 | TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type; | ||
| 1125 | TypeTableEntry *wanted_int_type; | ||
| 1126 | if (tag_type->id == TypeTableEntryIdEnumTag) { | ||
| 1127 | wanted_int_type = tag_type->data.enum_tag.int_type; | ||
| 1128 | } else if (tag_type->id == TypeTableEntryIdInt) { | ||
| 1129 | wanted_int_type = tag_type; | ||
| 1130 | } else { | ||
| 1131 | zig_unreachable(); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); | ||
| 1135 | return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), | ||
| 1136 | instruction->target->value.type, wanted_int_type, target_val); | ||
| 1137 | } | ||
| 1138 | |||
| 1125 | static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, | 1139 | static LLVMValueRef ir_render_unreachable(CodeGen *g, IrExecutable *executable, |
| 1126 | IrInstructionUnreachable *unreachable_instruction) | 1140 | IrInstructionUnreachable *unreachable_instruction) |
| 1127 | { | 1141 | { |
| ... | @@ -2359,6 +2373,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -2359,6 +2373,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2359 | return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction); | 2373 | return ir_render_ptr_to_int(g, executable, (IrInstructionPtrToInt *)instruction); |
| 2360 | case IrInstructionIdIntToPtr: | 2374 | case IrInstructionIdIntToPtr: |
| 2361 | return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction); | 2375 | return ir_render_int_to_ptr(g, executable, (IrInstructionIntToPtr *)instruction); |
| 2376 | case IrInstructionIdIntToEnum: | ||
| 2377 | return ir_render_int_to_enum(g, executable, (IrInstructionIntToEnum *)instruction); | ||
| 2362 | case IrInstructionIdContainerInitList: | 2378 | case IrInstructionIdContainerInitList: |
| 2363 | return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); | 2379 | return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); |
| 2364 | case IrInstructionIdSwitchVar: | 2380 | case IrInstructionIdSwitchVar: |
src/ir.cpp+40-11| ... | @@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) { | ... | @@ -468,6 +468,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToPtr *) { |
| 468 | return IrInstructionIdIntToPtr; | 468 | return IrInstructionIdIntToPtr; |
| 469 | } | 469 | } |
| 470 | 470 | ||
| 471 | static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) { | ||
| 472 | return IrInstructionIdIntToEnum; | ||
| 473 | } | ||
| 474 | |||
| 471 | template<typename T> | 475 | template<typename T> |
| 472 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { | 476 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 473 | T *special_instruction = allocate<T>(1); | 477 | T *special_instruction = allocate<T>(1); |
| ... | @@ -1932,6 +1936,18 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -1932,6 +1936,18 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode |
| 1932 | return &instruction->base; | 1936 | return &instruction->base; |
| 1933 | } | 1937 | } |
| 1934 | 1938 | ||
| 1939 | static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 1940 | IrInstruction *target) | ||
| 1941 | { | ||
| 1942 | IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>( | ||
| 1943 | irb, scope, source_node); | ||
| 1944 | instruction->target = target; | ||
| 1945 | |||
| 1946 | ir_ref_instruction(target); | ||
| 1947 | |||
| 1948 | return &instruction->base; | ||
| 1949 | } | ||
| 1950 | |||
| 1935 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 1951 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 1936 | results[ReturnKindUnconditional] = 0; | 1952 | results[ReturnKindUnconditional] = 0; |
| 1937 | results[ReturnKindError] = 0; | 1953 | results[ReturnKindError] = 0; |
| ... | @@ -4720,16 +4736,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, | ... | @@ -4720,16 +4736,6 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, |
| 4720 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); | 4736 | bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); |
| 4721 | const_val->special = ConstValSpecialStatic; | 4737 | const_val->special = ConstValSpecialStatic; |
| 4722 | break; | 4738 | break; |
| 4723 | case CastOpIntToEnum: | ||
| 4724 | { | ||
| 4725 | uint64_t value = other_val->data.x_bignum.data.x_uint; | ||
| 4726 | assert(new_type->id == TypeTableEntryIdEnum); | ||
| 4727 | assert(value < new_type->data.enumeration.src_field_count); | ||
| 4728 | const_val->data.x_enum.tag = value; | ||
| 4729 | const_val->data.x_enum.payload = NULL; | ||
| 4730 | const_val->special = ConstValSpecialStatic; | ||
| 4731 | break; | ||
| 4732 | } | ||
| 4733 | } | 4739 | } |
| 4734 | } | 4740 | } |
| 4735 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, | 4741 | static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| ... | @@ -5311,6 +5317,27 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -5311,6 +5317,27 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc |
| 5311 | return result; | 5317 | return result; |
| 5312 | } | 5318 | } |
| 5313 | 5319 | ||
| 5320 | static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 5321 | IrInstruction *target, TypeTableEntry *wanted_type) | ||
| 5322 | { | ||
| 5323 | assert(wanted_type->id == TypeTableEntryIdEnum); | ||
| 5324 | |||
| 5325 | if (instr_is_comptime(target)) { | ||
| 5326 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | ||
| 5327 | if (!val) | ||
| 5328 | return ira->codegen->invalid_instruction; | ||
| 5329 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 5330 | source_instr->source_node, wanted_type, val->depends_on_compile_var); | ||
| 5331 | result->value.data.x_enum.tag = val->data.x_bignum.data.x_uint; | ||
| 5332 | return result; | ||
| 5333 | } | ||
| 5334 | |||
| 5335 | IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope, | ||
| 5336 | source_instr->source_node, target); | ||
| 5337 | result->value.type = wanted_type; | ||
| 5338 | return result; | ||
| 5339 | } | ||
| 5340 | |||
| 5314 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, | 5341 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 5315 | TypeTableEntry *wanted_type, IrInstruction *value) | 5342 | TypeTableEntry *wanted_type, IrInstruction *value) |
| 5316 | { | 5343 | { |
| ... | @@ -5533,7 +5560,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -5533,7 +5560,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 5533 | wanted_type->id == TypeTableEntryIdEnum && | 5560 | wanted_type->id == TypeTableEntryIdEnum && |
| 5534 | wanted_type->data.enumeration.gen_field_count == 0) | 5561 | wanted_type->data.enumeration.gen_field_count == 0) |
| 5535 | { | 5562 | { |
| 5536 | return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false); | 5563 | return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type); |
| 5537 | } | 5564 | } |
| 5538 | 5565 | ||
| 5539 | // explicit cast from enum type with no payload to integer | 5566 | // explicit cast from enum type with no payload to integer |
| ... | @@ -10016,6 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -10016,6 +10043,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 10016 | case IrInstructionIdWidenOrShorten: | 10043 | case IrInstructionIdWidenOrShorten: |
| 10017 | case IrInstructionIdIntToPtr: | 10044 | case IrInstructionIdIntToPtr: |
| 10018 | case IrInstructionIdPtrToInt: | 10045 | case IrInstructionIdPtrToInt: |
| 10046 | case IrInstructionIdIntToEnum: | ||
| 10019 | case IrInstructionIdStructInit: | 10047 | case IrInstructionIdStructInit: |
| 10020 | case IrInstructionIdStructFieldPtr: | 10048 | case IrInstructionIdStructFieldPtr: |
| 10021 | case IrInstructionIdEnumFieldPtr: | 10049 | case IrInstructionIdEnumFieldPtr: |
| ... | @@ -10325,6 +10353,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -10325,6 +10353,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 10325 | case IrInstructionIdWidenOrShorten: | 10353 | case IrInstructionIdWidenOrShorten: |
| 10326 | case IrInstructionIdPtrToInt: | 10354 | case IrInstructionIdPtrToInt: |
| 10327 | case IrInstructionIdIntToPtr: | 10355 | case IrInstructionIdIntToPtr: |
| 10356 | case IrInstructionIdIntToEnum: | ||
| 10328 | return false; | 10357 | return false; |
| 10329 | case IrInstructionIdAsm: | 10358 | case IrInstructionIdAsm: |
| 10330 | { | 10359 | { |
src/ir_print.cpp+9| ... | @@ -952,6 +952,12 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction | ... | @@ -952,6 +952,12 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction |
| 952 | fprintf(irp->f, ")"); | 952 | fprintf(irp->f, ")"); |
| 953 | } | 953 | } |
| 954 | 954 | ||
| 955 | static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) { | ||
| 956 | fprintf(irp->f, "@intToEnum("); | ||
| 957 | ir_print_other_instruction(irp, instruction->target); | ||
| 958 | fprintf(irp->f, ")"); | ||
| 959 | } | ||
| 960 | |||
| 955 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 961 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 956 | ir_print_prefix(irp, instruction); | 962 | ir_print_prefix(irp, instruction); |
| 957 | switch (instruction->id) { | 963 | switch (instruction->id) { |
| ... | @@ -1203,6 +1209,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1203,6 +1209,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1203 | case IrInstructionIdIntToPtr: | 1209 | case IrInstructionIdIntToPtr: |
| 1204 | ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction); | 1210 | ir_print_int_to_ptr(irp, (IrInstructionIntToPtr *)instruction); |
| 1205 | break; | 1211 | break; |
| 1212 | case IrInstructionIdIntToEnum: | ||
| 1213 | ir_print_int_to_enum(irp, (IrInstructionIntToEnum *)instruction); | ||
| 1214 | break; | ||
| 1206 | } | 1215 | } |
| 1207 | fprintf(irp->f, "\n"); | 1216 | fprintf(irp->f, "\n"); |
| 1208 | } | 1217 | } |
test/cases/enum.zig+17| ... | @@ -96,6 +96,23 @@ fn shouldEqual(n: Number, expected: usize) { | ... | @@ -96,6 +96,23 @@ fn shouldEqual(n: Number, expected: usize) { |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | 98 | ||
| 99 | fn intToEnum() { | ||
| 100 | @setFnTest(this); | ||
| 101 | |||
| 102 | testIntToEnumEval(3); | ||
| 103 | } | ||
| 104 | fn testIntToEnumEval(x: i32) { | ||
| 105 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | ||
| 106 | } | ||
| 107 | const IntToEnumNumber = enum { | ||
| 108 | Zero, | ||
| 109 | One, | ||
| 110 | Two, | ||
| 111 | Three, | ||
| 112 | Four, | ||
| 113 | }; | ||
| 114 | |||
| 115 | |||
| 99 | // TODO import from std | 116 | // TODO import from std |
| 100 | fn assert(ok: bool) { | 117 | fn assert(ok: bool) { |
| 101 | if (!ok) | 118 | if (!ok) |
test/self_hosted.zig-17| ... | @@ -80,20 +80,3 @@ fn castSliceToU8Slice() { | ... | @@ -80,20 +80,3 @@ fn castSliceToU8Slice() { |
| 80 | assert(bytes[10] == @maxValue(u8)); | 80 | assert(bytes[10] == @maxValue(u8)); |
| 81 | assert(bytes[11] == @maxValue(u8)); | 81 | assert(bytes[11] == @maxValue(u8)); |
| 82 | } | 82 | } |
| 83 | |||
| 84 | // TODO not passing | ||
| 85 | fn intToEnum() { | ||
| 86 | @setFnTest(this); | ||
| 87 | |||
| 88 | testIntToEnumEval(3); | ||
| 89 | } | ||
| 90 | fn testIntToEnumEval(x: i32) { | ||
| 91 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | ||
| 92 | } | ||
| 93 | const IntToEnumNumber = enum { | ||
| 94 | Zero, | ||
| 95 | One, | ||
| 96 | Two, | ||
| 97 | Three, | ||
| 98 | Four, | ||
| 99 | }; |