authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-03-21 18:00:19+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-22 19:06:22-04:00
log6a89751025abc074d31bbbab5b01a7e701f1abce
treee296b2b28d230deb4370e120b52261b5d7866f78
parenta8fa1ecd89eebd444736d73da4ebf24af74daea8

ir: Implement cast from anon struct to union


2 files changed, 98 insertions(+), 4 deletions(-)

src/ir.cpp+70-4
......@@ -276,6 +276,11 @@ static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf
276276 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime);
277277static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var,
278278 IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime);
279static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instruction,
280 AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstGen *field_result_loc,
281 IrInstGen *result_loc);
282static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr,
283 IrInstGen *struct_operand, TypeStructField *field);
279284
280285static void destroy_instruction_src(IrInstSrc *inst) {
281286 switch (inst->id) {
......@@ -14445,10 +14450,71 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* so
1444514450}
1444614451
1444714452static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr,
14448 IrInstGen *value, ZigType *wanted_type)
14453 IrInstGen *value, ZigType *union_type)
1444914454{
14450 ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to union"));
14451 return ira->codegen->invalid_inst_gen;
14455 Error err;
14456 ZigType *struct_type = value->value->type;
14457
14458 assert(struct_type->id == ZigTypeIdStruct);
14459 assert(union_type->id == ZigTypeIdUnion);
14460 assert(struct_type->data.structure.src_field_count == 1);
14461
14462 TypeStructField *only_field = struct_type->data.structure.fields[0];
14463
14464 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown)))
14465 return ira->codegen->invalid_inst_gen;
14466
14467 TypeUnionField *union_field = find_union_type_field(union_type, only_field->name);
14468 if (union_field == nullptr) {
14469 ir_add_error_node(ira, only_field->decl_node,
14470 buf_sprintf("no member named '%s' in union '%s'",
14471 buf_ptr(only_field->name), buf_ptr(&union_type->name)));
14472 return ira->codegen->invalid_inst_gen;
14473 }
14474
14475 ZigType *payload_type = resolve_union_field_type(ira->codegen, union_field);
14476 if (payload_type == nullptr)
14477 return ira->codegen->invalid_inst_gen;
14478
14479 IrInstGen *field_value = ir_analyze_struct_value_field_value(ira, source_instr, value, only_field);
14480 if (type_is_invalid(field_value->value->type))
14481 return ira->codegen->invalid_inst_gen;
14482
14483 IrInstGen *casted_value = ir_implicit_cast(ira, field_value, payload_type);
14484 if (type_is_invalid(casted_value->value->type))
14485 return ira->codegen->invalid_inst_gen;
14486
14487 if (instr_is_comptime(casted_value)) {
14488 ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad);
14489 if (val == nullptr)
14490 return ira->codegen->invalid_inst_gen;
14491
14492 IrInstGen *result = ir_const(ira, source_instr, union_type);
14493 bigint_init_bigint(&result->value->data.x_union.tag, &union_field->enum_field->value);
14494 result->value->data.x_union.payload = val;
14495
14496 val->parent.id = ConstParentIdUnion;
14497 val->parent.data.p_union.union_val = result->value;
14498
14499 return result;
14500 }
14501
14502 IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(),
14503 union_type, nullptr, true, true);
14504 if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) {
14505 return ira->codegen->invalid_inst_gen;
14506 }
14507
14508 IrInstGen *payload_ptr = ir_analyze_container_field_ptr(ira, only_field->name, source_instr,
14509 result_loc_inst, source_instr, union_type, true);
14510 if (type_is_invalid(payload_ptr->value->type))
14511 return ira->codegen->invalid_inst_gen;
14512
14513 IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, payload_ptr, casted_value, false);
14514 if (type_is_invalid(store_ptr_inst->value->type))
14515 return ira->codegen->invalid_inst_gen;
14516
14517 return ir_get_deref(ira, source_instr, result_loc_inst, nullptr);
1445214518}
1445314519
1445414520// Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work,
......@@ -23050,7 +23116,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi
2305023116 Error err;
2305123117 assert(union_type->id == ZigTypeIdUnion);
2305223118
23053 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
23119 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown)))
2305423120 return ira->codegen->invalid_inst_gen;
2305523121
2305623122 TypeUnionField *type_field = find_union_type_field(union_type, field_name);
test/stage1/behavior/union.zig+28
......@@ -1,5 +1,6 @@
11const std = @import("std");
22const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;
34
45const Value = union(enum) {
56 Int: u64,
......@@ -638,3 +639,30 @@ test "runtime tag name with single field" {
638639 var v = U{ .A = 42 };
639640 expect(std.mem.eql(u8, @tagName(v), "A"));
640641}
642
643test "cast from anonymous struct to union" {
644 const S = struct {
645 const U = union(enum) {
646 A: u32,
647 B: []const u8,
648 C: void,
649 };
650 fn doTheTest() void {
651 var y: u32 = 42;
652 const t0 = .{ .A = 123 };
653 const t1 = .{ .B = "foo" };
654 const t2 = .{ .C = {} };
655 const t3 = .{ .A = y };
656 const x0: U = t0;
657 var x1: U = t1;
658 const x2: U = t2;
659 var x3: U = t3;
660 expect(x0.A == 123);
661 expect(std.mem.eql(u8, x1.B, "foo"));
662 expect(x2 == .C);
663 expect(x3.A == y);
664 }
665 };
666 S.doTheTest();
667 comptime S.doTheTest();
668}