| author | |
| committer | |
| log | 6018dbd3391d1e71eef650aff700eab53074c308 |
| tree | 4d3bd0c5bb0a55a7ad144270eed99d90855efd45 |
| parent | 08d531143f0b373cbc54e037fa526fb00d9db398 |
| parent | 960914a073c367883c9fdf54e900890a6aefc05f |
6 files changed, 171 insertions(+), 20 deletions(-)
src/analyze.cpp+10-5| ... | @@ -2244,12 +2244,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2244,12 +2244,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2244 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); | 2244 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); |
| 2245 | if (type_is_invalid(enum_type)) { | 2245 | if (type_is_invalid(enum_type)) { |
| 2246 | union_type->data.unionation.is_invalid = true; | 2246 | union_type->data.unionation.is_invalid = true; |
| 2247 | union_type->data.unionation.embedded_in_current = false; | ||
| 2248 | return; | 2247 | return; |
| 2249 | } | 2248 | } |
| 2250 | if (enum_type->id != TypeTableEntryIdEnum) { | 2249 | if (enum_type->id != TypeTableEntryIdEnum) { |
| 2251 | union_type->data.unionation.is_invalid = true; | 2250 | union_type->data.unionation.is_invalid = true; |
| 2252 | union_type->data.unionation.embedded_in_current = false; | ||
| 2253 | add_node_error(g, enum_type_node, | 2251 | add_node_error(g, enum_type_node, |
| 2254 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); | 2252 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); |
| 2255 | return; | 2253 | return; |
| ... | @@ -3319,7 +3317,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { | ... | @@ -3319,7 +3317,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3319 | 3317 | ||
| 3320 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | 3318 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3321 | assert(type_entry->id == TypeTableEntryIdUnion); | 3319 | assert(type_entry->id == TypeTableEntryIdUnion); |
| 3322 | assert(type_entry->data.unionation.complete); | 3320 | assert(type_entry->data.unionation.zero_bits_known); |
| 3323 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | 3321 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { |
| 3324 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | 3322 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; |
| 3325 | if (buf_eql_buf(field->enum_field->name, name)) { | 3323 | if (buf_eql_buf(field->enum_field->name, name)) { |
| ... | @@ -3331,7 +3329,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | ... | @@ -3331,7 +3329,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3331 | 3329 | ||
| 3332 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { | 3330 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { |
| 3333 | assert(type_entry->id == TypeTableEntryIdUnion); | 3331 | assert(type_entry->id == TypeTableEntryIdUnion); |
| 3334 | assert(type_entry->data.unionation.complete); | 3332 | assert(type_entry->data.unionation.zero_bits_known); |
| 3335 | assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); | 3333 | assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); |
| 3336 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | 3334 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { |
| 3337 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | 3335 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; |
| ... | @@ -3888,7 +3886,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -3888,7 +3886,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3888 | return false; | 3886 | return false; |
| 3889 | case TypeTableEntryIdArray: | 3887 | case TypeTableEntryIdArray: |
| 3890 | case TypeTableEntryIdStruct: | 3888 | case TypeTableEntryIdStruct: |
| 3891 | case TypeTableEntryIdUnion: | ||
| 3892 | return type_has_bits(type_entry); | 3889 | return type_has_bits(type_entry); |
| 3893 | case TypeTableEntryIdErrorUnion: | 3890 | case TypeTableEntryIdErrorUnion: |
| 3894 | return type_has_bits(type_entry->data.error.child_type); | 3891 | return type_has_bits(type_entry->data.error.child_type); |
| ... | @@ -3896,6 +3893,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -3896,6 +3893,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3896 | return type_has_bits(type_entry->data.maybe.child_type) && | 3893 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 3897 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && | 3894 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && |
| 3898 | type_entry->data.maybe.child_type->id != TypeTableEntryIdFn; | 3895 | type_entry->data.maybe.child_type->id != TypeTableEntryIdFn; |
| 3896 | case TypeTableEntryIdUnion: | ||
| 3897 | assert(type_entry->data.unionation.complete); | ||
| 3898 | if (type_entry->data.unionation.gen_field_count == 0) | ||
| 3899 | return false; | ||
| 3900 | if (!type_has_bits(type_entry)) | ||
| 3901 | return false; | ||
| 3902 | return true; | ||
| 3903 | |||
| 3899 | } | 3904 | } |
| 3900 | zig_unreachable(); | 3905 | zig_unreachable(); |
| 3901 | } | 3906 | } |
src/codegen.cpp+8-8| ... | @@ -3946,8 +3946,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3946,8 +3946,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3946 | case TypeTableEntryIdUnion: | 3946 | case TypeTableEntryIdUnion: |
| 3947 | { | 3947 | { |
| 3948 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; | 3948 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; |
| 3949 | ConstExprValue *payload_value = const_val->data.x_union.payload; | ||
| 3950 | assert(payload_value != nullptr); | ||
| 3951 | 3949 | ||
| 3952 | if (type_entry->data.unionation.gen_field_count == 0) { | 3950 | if (type_entry->data.unionation.gen_field_count == 0) { |
| 3953 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | 3951 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { |
| ... | @@ -3960,7 +3958,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3960,7 +3958,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3960 | 3958 | ||
| 3961 | LLVMValueRef union_value_ref; | 3959 | LLVMValueRef union_value_ref; |
| 3962 | bool make_unnamed_struct; | 3960 | bool make_unnamed_struct; |
| 3963 | if (!type_has_bits(payload_value->type)) { | 3961 | ConstExprValue *payload_value = const_val->data.x_union.payload; |
| 3962 | if (payload_value == nullptr || !type_has_bits(payload_value->type)) { | ||
| 3964 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) | 3963 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) |
| 3965 | return LLVMGetUndef(type_entry->type_ref); | 3964 | return LLVMGetUndef(type_entry->type_ref); |
| 3966 | 3965 | ||
| ... | @@ -5298,18 +5297,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) { | ... | @@ -5298,18 +5297,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) { |
| 5298 | 5297 | ||
| 5299 | ZigList<ErrorMsg *> errors = {0}; | 5298 | ZigList<ErrorMsg *> errors = {0}; |
| 5300 | int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); | 5299 | int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); |
| 5301 | if (err) { | ||
| 5302 | fprintf(stderr, "unable to parse C file: %s\n", err_str(err)); | ||
| 5303 | exit(1); | ||
| 5304 | } | ||
| 5305 | 5300 | ||
| 5306 | if (errors.length > 0) { | 5301 | if (err == ErrorCCompileErrors && errors.length > 0) { |
| 5307 | for (size_t i = 0; i < errors.length; i += 1) { | 5302 | for (size_t i = 0; i < errors.length; i += 1) { |
| 5308 | ErrorMsg *err_msg = errors.at(i); | 5303 | ErrorMsg *err_msg = errors.at(i); |
| 5309 | print_err_msg(err_msg, g->err_color); | 5304 | print_err_msg(err_msg, g->err_color); |
| 5310 | } | 5305 | } |
| 5311 | exit(1); | 5306 | exit(1); |
| 5312 | } | 5307 | } |
| 5308 | |||
| 5309 | if (err) { | ||
| 5310 | fprintf(stderr, "unable to parse C file: %s\n", err_str(err)); | ||
| 5311 | exit(1); | ||
| 5312 | } | ||
| 5313 | } | 5313 | } |
| 5314 | 5314 | ||
| 5315 | static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) { | 5315 | static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) { |
src/ir.cpp+98-7| ... | @@ -7468,6 +7468,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, | ... | @@ -7468,6 +7468,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, |
| 7468 | } | 7468 | } |
| 7469 | } | 7469 | } |
| 7470 | 7470 | ||
| 7471 | // implicit enum to union which has the enum as the tag type | ||
| 7472 | if (expected_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum && | ||
| 7473 | (expected_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 7474 | expected_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 7475 | { | ||
| 7476 | type_ensure_zero_bits_known(ira->codegen, expected_type); | ||
| 7477 | if (expected_type->data.unionation.tag_type == actual_type) { | ||
| 7478 | return ImplicitCastMatchResultYes; | ||
| 7479 | } | ||
| 7480 | } | ||
| 7481 | |||
| 7471 | // implicit undefined literal to anything | 7482 | // implicit undefined literal to anything |
| 7472 | if (actual_type->id == TypeTableEntryIdUndefLit) { | 7483 | if (actual_type->id == TypeTableEntryIdUndefLit) { |
| 7473 | return ImplicitCastMatchResultYes; | 7484 | return ImplicitCastMatchResultYes; |
| ... | @@ -8370,6 +8381,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc | ... | @@ -8370,6 +8381,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc |
| 8370 | return result; | 8381 | return result; |
| 8371 | } | 8382 | } |
| 8372 | 8383 | ||
| 8384 | static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr, | ||
| 8385 | IrInstruction *target, TypeTableEntry *wanted_type) | ||
| 8386 | { | ||
| 8387 | assert(wanted_type->id == TypeTableEntryIdUnion); | ||
| 8388 | assert(target->value.type->id == TypeTableEntryIdEnum); | ||
| 8389 | |||
| 8390 | if (instr_is_comptime(target)) { | ||
| 8391 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | ||
| 8392 | if (!val) | ||
| 8393 | return ira->codegen->invalid_instruction; | ||
| 8394 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); | ||
| 8395 | assert(union_field != nullptr); | ||
| 8396 | type_ensure_zero_bits_known(ira->codegen, union_field->type_entry); | ||
| 8397 | if (!union_field->type_entry->zero_bits) { | ||
| 8398 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( | ||
| 8399 | union_field->enum_field->decl_index); | ||
| 8400 | ErrorMsg *msg = ir_add_error(ira, source_instr, | ||
| 8401 | buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", | ||
| 8402 | buf_ptr(&wanted_type->name), | ||
| 8403 | buf_ptr(&union_field->type_entry->name), | ||
| 8404 | buf_ptr(union_field->name))); | ||
| 8405 | add_error_note(ira->codegen, msg, field_node, | ||
| 8406 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); | ||
| 8407 | return ira->codegen->invalid_instruction; | ||
| 8408 | } | ||
| 8409 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | ||
| 8410 | source_instr->source_node, wanted_type); | ||
| 8411 | result->value.special = ConstValSpecialStatic; | ||
| 8412 | result->value.type = wanted_type; | ||
| 8413 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); | ||
| 8414 | return result; | ||
| 8415 | } | ||
| 8416 | |||
| 8417 | // if the union has all fields 0 bits, we can do it | ||
| 8418 | // and in fact it's a noop cast because the union value is just the enum value | ||
| 8419 | if (wanted_type->data.unionation.gen_field_count == 0) { | ||
| 8420 | IrInstruction *result = ir_build_cast(&ira->new_irb, target->scope, target->source_node, wanted_type, target, CastOpNoop); | ||
| 8421 | result->value.type = wanted_type; | ||
| 8422 | return result; | ||
| 8423 | } | ||
| 8424 | |||
| 8425 | ErrorMsg *msg = ir_add_error(ira, source_instr, | ||
| 8426 | buf_sprintf("runtime cast to union '%s' which has non-void fields", | ||
| 8427 | buf_ptr(&wanted_type->name))); | ||
| 8428 | for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { | ||
| 8429 | TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; | ||
| 8430 | if (type_has_bits(union_field->type_entry)) { | ||
| 8431 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); | ||
| 8432 | add_error_note(ira->codegen, msg, field_node, | ||
| 8433 | buf_sprintf("field '%s' has type '%s'", | ||
| 8434 | buf_ptr(union_field->name), | ||
| 8435 | buf_ptr(&union_field->type_entry->name))); | ||
| 8436 | } | ||
| 8437 | } | ||
| 8438 | return ira->codegen->invalid_instruction; | ||
| 8439 | } | ||
| 8440 | |||
| 8373 | static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr, | 8441 | static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr, |
| 8374 | IrInstruction *target, TypeTableEntry *wanted_type) | 8442 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 8375 | { | 8443 | { |
| ... | @@ -8426,14 +8494,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour | ... | @@ -8426,14 +8494,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 8426 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | 8494 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 8427 | if (!val) | 8495 | if (!val) |
| 8428 | return ira->codegen->invalid_instruction; | 8496 | return ira->codegen->invalid_instruction; |
| 8429 | BigInt enum_member_count; | 8497 | |
| 8430 | bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count); | 8498 | TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint); |
| 8431 | if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) { | 8499 | if (field == nullptr) { |
| 8432 | Buf *val_buf = buf_alloc(); | 8500 | Buf *val_buf = buf_alloc(); |
| 8433 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); | 8501 | bigint_append_buf(val_buf, &val->data.x_bigint, 10); |
| 8434 | ir_add_error(ira, source_instr, | 8502 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 8435 | buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields", | 8503 | buf_sprintf("enum '%s' has no tag matching integer value %s", |
| 8436 | buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count)); | 8504 | buf_ptr(&wanted_type->name), buf_ptr(val_buf))); |
| 8505 | add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node, | ||
| 8506 | buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name))); | ||
| 8437 | return ira->codegen->invalid_instruction; | 8507 | return ira->codegen->invalid_instruction; |
| 8438 | } | 8508 | } |
| 8439 | 8509 | ||
| ... | @@ -8842,7 +8912,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8842,7 +8912,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8842 | if (actual_type->id == TypeTableEntryIdNumLitFloat || | 8912 | if (actual_type->id == TypeTableEntryIdNumLitFloat || |
| 8843 | actual_type->id == TypeTableEntryIdNumLitInt) | 8913 | actual_type->id == TypeTableEntryIdNumLitInt) |
| 8844 | { | 8914 | { |
| 8845 | if (wanted_type->id == TypeTableEntryIdPointer && | 8915 | if (wanted_type->id == TypeTableEntryIdEnum) { |
| 8916 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value); | ||
| 8917 | if (type_is_invalid(cast1->value.type)) | ||
| 8918 | return ira->codegen->invalid_instruction; | ||
| 8919 | |||
| 8920 | IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); | ||
| 8921 | if (type_is_invalid(cast2->value.type)) | ||
| 8922 | return ira->codegen->invalid_instruction; | ||
| 8923 | |||
| 8924 | return cast2; | ||
| 8925 | } else if (wanted_type->id == TypeTableEntryIdPointer && | ||
| 8846 | wanted_type->data.pointer.is_const) | 8926 | wanted_type->data.pointer.is_const) |
| 8847 | { | 8927 | { |
| 8848 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); | 8928 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value); |
| ... | @@ -8912,6 +8992,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -8912,6 +8992,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8912 | } | 8992 | } |
| 8913 | } | 8993 | } |
| 8914 | 8994 | ||
| 8995 | // explicit enum to union which has the enum as the tag type | ||
| 8996 | if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum && | ||
| 8997 | (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || | ||
| 8998 | wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | ||
| 8999 | { | ||
| 9000 | type_ensure_zero_bits_known(ira->codegen, wanted_type); | ||
| 9001 | if (wanted_type->data.unionation.tag_type == actual_type) { | ||
| 9002 | return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type); | ||
| 9003 | } | ||
| 9004 | } | ||
| 9005 | |||
| 8915 | // explicit cast from undefined to anything | 9006 | // explicit cast from undefined to anything |
| 8916 | if (actual_type->id == TypeTableEntryIdUndefLit) { | 9007 | if (actual_type->id == TypeTableEntryIdUndefLit) { |
| 8917 | return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); | 9008 | return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); |
test/cases/enum.zig+5| ... | @@ -344,3 +344,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) { | ... | @@ -344,3 +344,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) { |
| 344 | MultipleChoice2.Unspecified5 => 9, | 344 | MultipleChoice2.Unspecified5 => 9, |
| 345 | }); | 345 | }); |
| 346 | } | 346 | } |
| 347 | |||
| 348 | test "cast integer literal to enum" { | ||
| 349 | assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1); | ||
| 350 | assert(MultipleChoice2(40) == MultipleChoice2.B); | ||
| 351 | } |
test/cases/union.zig+7| ... | @@ -190,3 +190,10 @@ test "cast union to tag type of union" { | ... | @@ -190,3 +190,10 @@ test "cast union to tag type of union" { |
| 190 | fn testCastUnionToTagType(x: &const TheUnion) { | 190 | fn testCastUnionToTagType(x: &const TheUnion) { |
| 191 | assert(TheTag(*x) == TheTag.B); | 191 | assert(TheTag(*x) == TheTag.B); |
| 192 | } | 192 | } |
| 193 | |||
| 194 | test "cast tag type of union to union" { | ||
| 195 | var x: Value2 = Letter2.B; | ||
| 196 | assert(Letter2(x) == Letter2.B); | ||
| 197 | } | ||
| 198 | const Letter2 = enum { A, B, C }; | ||
| 199 | const Value2 = union(Letter2) { A: i32, B, C, }; |
test/compile_errors.zig+43| ... | @@ -2684,4 +2684,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2684,4 +2684,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2684 | , | 2684 | , |
| 2685 | ".tmp_source.zig:11:13: error: switch on union which has no attached enum", | 2685 | ".tmp_source.zig:11:13: error: switch on union which has no attached enum", |
| 2686 | ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); | 2686 | ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); |
| 2687 | |||
| 2688 | cases.add("enum in field count range but not matching tag", | ||
| 2689 | \\const Foo = enum(u32) { | ||
| 2690 | \\ A = 10, | ||
| 2691 | \\ B = 11, | ||
| 2692 | \\}; | ||
| 2693 | \\export fn entry() { | ||
| 2694 | \\ var x = Foo(0); | ||
| 2695 | \\} | ||
| 2696 | , | ||
| 2697 | ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0", | ||
| 2698 | ".tmp_source.zig:1:13: note: 'Foo' declared here"); | ||
| 2699 | |||
| 2700 | cases.add("comptime cast enum to union but field has payload", | ||
| 2701 | \\const Letter = enum { A, B, C }; | ||
| 2702 | \\const Value = union(Letter) { | ||
| 2703 | \\ A: i32, | ||
| 2704 | \\ B, | ||
| 2705 | \\ C, | ||
| 2706 | \\}; | ||
| 2707 | \\export fn entry() { | ||
| 2708 | \\ var x: Value = Letter.A; | ||
| 2709 | \\} | ||
| 2710 | , | ||
| 2711 | ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'", | ||
| 2712 | ".tmp_source.zig:3:5: note: field 'A' declared here"); | ||
| 2713 | |||
| 2714 | cases.add("runtime cast to union which has non-void fields", | ||
| 2715 | \\const Letter = enum { A, B, C }; | ||
| 2716 | \\const Value = union(Letter) { | ||
| 2717 | \\ A: i32, | ||
| 2718 | \\ B, | ||
| 2719 | \\ C, | ||
| 2720 | \\}; | ||
| 2721 | \\export fn entry() { | ||
| 2722 | \\ foo(Letter.A); | ||
| 2723 | \\} | ||
| 2724 | \\fn foo(l: Letter) { | ||
| 2725 | \\ var x: Value = l; | ||
| 2726 | \\} | ||
| 2727 | , | ||
| 2728 | ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields", | ||
| 2729 | ".tmp_source.zig:3:5: note: field 'A' has type 'i32'"); | ||
| 2687 | } | 2730 | } |