authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-15 16:48:19-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-15 16:52:18-04:00
log2bb3e1aff4976b2d04fb08a46d9221c77da0b204
tree55df9c2d9ad0860d6ec93af616c8a5e8c4ed61c3
parente7207bc267d90b5be009fcd937b86cde9bf9ae77

stage1: implement type coercion of anon struct literal to struct

closes #3672

2 files changed, 171 insertions(+), 8 deletions(-)

src/ir.cpp+138-8
...@@ -286,6 +286,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so...@@ -286,6 +286,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so
286 IrInstGen *struct_operand, TypeStructField *field);286 IrInstGen *struct_operand, TypeStructField *field);
287static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);287static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);
288static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);288static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);
289static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field);
289290
290#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)291#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)
291#define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)292#define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)
...@@ -14703,10 +14704,139 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou...@@ -14703,10 +14704,139 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou
14703}14704}
1470414705
14705static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* source_instr,14706static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* source_instr,
14706 IrInstGen *value, ZigType *wanted_type)14707 IrInstGen *struct_operand, ZigType *wanted_type)
14707{14708{
14708 ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to struct"));14709 Error err;
14709 return ira->codegen->invalid_inst_gen;14710
14711 IrInstGen *struct_ptr = ir_get_ref(ira, source_instr, struct_operand, true, false);
14712 if (type_is_invalid(struct_ptr->value->type))
14713 return ira->codegen->invalid_inst_gen;
14714
14715 if (wanted_type->data.structure.resolve_status == ResolveStatusBeingInferred) {
14716 ir_add_error(ira, source_instr, buf_sprintf("type coercion of anon struct literal to inferred struct"));
14717 return ira->codegen->invalid_inst_gen;
14718 }
14719
14720 if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))
14721 return ira->codegen->invalid_inst_gen;
14722
14723 size_t actual_field_count = wanted_type->data.structure.src_field_count;
14724 size_t instr_field_count = struct_operand->value->type->data.structure.src_field_count;
14725
14726 bool need_comptime = ir_should_inline(ira->old_irb.exec, source_instr->scope)
14727 || type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes;
14728 bool is_comptime = true;
14729
14730 // Determine if the struct_operand will be comptime.
14731 // Also emit compile errors for missing fields and duplicate fields.
14732 AstNode **field_assign_nodes = heap::c_allocator.allocate<AstNode *>(actual_field_count);
14733 ZigValue **field_values = heap::c_allocator.allocate<ZigValue *>(actual_field_count);
14734 IrInstGen **casted_fields = heap::c_allocator.allocate<IrInstGen *>(actual_field_count);
14735 IrInstGen *const_result = ir_const(ira, source_instr, wanted_type);
14736
14737 for (size_t i = 0; i < instr_field_count; i += 1) {
14738 TypeStructField *src_field = struct_operand->value->type->data.structure.fields[i];
14739 TypeStructField *dst_field = find_struct_type_field(wanted_type, src_field->name);
14740 if (dst_field == nullptr) {
14741 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("no field named '%s' in struct '%s'",
14742 buf_ptr(src_field->name), buf_ptr(&wanted_type->name)));
14743 if (wanted_type->data.structure.decl_node) {
14744 add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node,
14745 buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name)));
14746 }
14747 add_error_note(ira->codegen, msg, src_field->decl_node,
14748 buf_sprintf("field '%s' declared here", buf_ptr(src_field->name)));
14749 return ira->codegen->invalid_inst_gen;
14750 }
14751
14752 ir_assert(src_field->decl_node != nullptr, source_instr);
14753 AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index];
14754 if (existing_assign_node != nullptr) {
14755 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("duplicate field"));
14756 add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here"));
14757 return ira->codegen->invalid_inst_gen;
14758 }
14759 field_assign_nodes[dst_field->src_index] = src_field->decl_node;
14760
14761 IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, src_field, struct_ptr,
14762 struct_operand->value->type, false);
14763 if (type_is_invalid(field_ptr->value->type))
14764 return ira->codegen->invalid_inst_gen;
14765 IrInstGen *field_value = ir_get_deref(ira, source_instr, field_ptr, nullptr);
14766 if (type_is_invalid(field_value->value->type))
14767 return ira->codegen->invalid_inst_gen;
14768 IrInstGen *casted_value = ir_implicit_cast(ira, field_value, dst_field->type_entry);
14769 if (type_is_invalid(casted_value->value->type))
14770 return ira->codegen->invalid_inst_gen;
14771
14772 casted_fields[dst_field->src_index] = casted_value;
14773 if (need_comptime || instr_is_comptime(casted_value)) {
14774 ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk);
14775 if (field_val == nullptr)
14776 return ira->codegen->invalid_inst_gen;
14777 field_val->parent.id = ConstParentIdStruct;
14778 field_val->parent.data.p_struct.struct_val = const_result->value;
14779 field_val->parent.data.p_struct.field_index = dst_field->src_index;
14780 field_values[dst_field->src_index] = field_val;
14781 } else {
14782 is_comptime = false;
14783 }
14784 }
14785
14786 bool any_missing = false;
14787 for (size_t i = 0; i < actual_field_count; i += 1) {
14788 if (field_assign_nodes[i] != nullptr) continue;
14789
14790 // look for a default field value
14791 TypeStructField *field = wanted_type->data.structure.fields[i];
14792 memoize_field_init_val(ira->codegen, wanted_type, field);
14793 if (field->init_val == nullptr) {
14794 ir_add_error(ira, source_instr,
14795 buf_sprintf("missing field: '%s'", buf_ptr(field->name)));
14796 any_missing = true;
14797 continue;
14798 }
14799 if (type_is_invalid(field->init_val->type))
14800 return ira->codegen->invalid_inst_gen;
14801 ZigValue *init_val_copy = ira->codegen->pass1_arena->create<ZigValue>();
14802 copy_const_val(ira->codegen, init_val_copy, field->init_val);
14803 init_val_copy->parent.id = ConstParentIdStruct;
14804 init_val_copy->parent.data.p_struct.struct_val = const_result->value;
14805 init_val_copy->parent.data.p_struct.field_index = i;
14806 field_values[i] = init_val_copy;
14807 casted_fields[i] = ir_const_move(ira, source_instr, init_val_copy);
14808 }
14809 if (any_missing)
14810 return ira->codegen->invalid_inst_gen;
14811
14812 if (is_comptime) {
14813 heap::c_allocator.deallocate(field_assign_nodes, actual_field_count);
14814 IrInstGen *const_result = ir_const(ira, source_instr, wanted_type);
14815 const_result->value->data.x_struct.fields = field_values;
14816 return const_result;
14817 }
14818
14819 IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(),
14820 wanted_type, nullptr, true, true);
14821 if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) {
14822 return ira->codegen->invalid_inst_gen;
14823 }
14824
14825 for (size_t i = 0; i < actual_field_count; i += 1) {
14826 TypeStructField *field = wanted_type->data.structure.fields[i];
14827 IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, result_loc_inst, wanted_type, true);
14828 if (type_is_invalid(field_ptr->value->type))
14829 return ira->codegen->invalid_inst_gen;
14830 IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, field_ptr, casted_fields[i], true);
14831 if (type_is_invalid(store_ptr_inst->value->type))
14832 return ira->codegen->invalid_inst_gen;
14833 }
14834
14835 heap::c_allocator.deallocate(field_assign_nodes, actual_field_count);
14836 heap::c_allocator.deallocate(field_values, actual_field_count);
14837 heap::c_allocator.deallocate(casted_fields, actual_field_count);
14838
14839 return ir_get_deref(ira, source_instr, result_loc_inst, nullptr);
14710}14840}
1471114841
14712static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr,14842static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr,
...@@ -14727,7 +14857,7 @@ static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* sou...@@ -14727,7 +14857,7 @@ static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* sou
14727 TypeUnionField *union_field = find_union_type_field(union_type, only_field->name);14857 TypeUnionField *union_field = find_union_type_field(union_type, only_field->name);
14728 if (union_field == nullptr) {14858 if (union_field == nullptr) {
14729 ir_add_error_node(ira, only_field->decl_node,14859 ir_add_error_node(ira, only_field->decl_node,
14730 buf_sprintf("no member named '%s' in union '%s'",14860 buf_sprintf("no field named '%s' in union '%s'",
14731 buf_ptr(only_field->name), buf_ptr(&union_type->name)));14861 buf_ptr(only_field->name), buf_ptr(&union_type->name)));
14732 return ira->codegen->invalid_inst_gen;14862 return ira->codegen->invalid_inst_gen;
14733 }14863 }
...@@ -22407,7 +22537,7 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel...@@ -22407,7 +22537,7 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel
22407 usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);22537 usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
22408 } else {22538 } else {
22409 ir_add_error_node(ira, source_node,22539 ir_add_error_node(ira, source_node,
22410 buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),22540 buf_sprintf("no field named '%s' in '%s'", buf_ptr(field_name),
22411 buf_ptr(&container_type->name)));22541 buf_ptr(&container_type->name)));
22412 return ira->codegen->invalid_inst_gen;22542 return ira->codegen->invalid_inst_gen;
22413 }22543 }
...@@ -23834,7 +23964,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi...@@ -23834,7 +23964,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi
23834 TypeUnionField *type_field = find_union_type_field(union_type, field_name);23964 TypeUnionField *type_field = find_union_type_field(union_type, field_name);
23835 if (type_field == nullptr) {23965 if (type_field == nullptr) {
23836 ir_add_error_node(ira, field_source_node,23966 ir_add_error_node(ira, field_source_node,
23837 buf_sprintf("no member named '%s' in union '%s'",23967 buf_sprintf("no field named '%s' in union '%s'",
23838 buf_ptr(field_name), buf_ptr(&union_type->name)));23968 buf_ptr(field_name), buf_ptr(&union_type->name)));
23839 return ira->codegen->invalid_inst_gen;23969 return ira->codegen->invalid_inst_gen;
23840 }23970 }
...@@ -23930,7 +24060,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc...@@ -23930,7 +24060,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
23930 TypeStructField *type_field = find_struct_type_field(container_type, field->name);24060 TypeStructField *type_field = find_struct_type_field(container_type, field->name);
23931 if (!type_field) {24061 if (!type_field) {
23932 ir_add_error_node(ira, field->source_node,24062 ir_add_error_node(ira, field->source_node,
23933 buf_sprintf("no member named '%s' in struct '%s'",24063 buf_sprintf("no field named '%s' in struct '%s'",
23934 buf_ptr(field->name), buf_ptr(&container_type->name)));24064 buf_ptr(field->name), buf_ptr(&container_type->name)));
23935 return ira->codegen->invalid_inst_gen;24065 return ira->codegen->invalid_inst_gen;
23936 }24066 }
...@@ -23965,7 +24095,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc...@@ -23965,7 +24095,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
23965 memoize_field_init_val(ira->codegen, container_type, field);24095 memoize_field_init_val(ira->codegen, container_type, field);
23966 if (field->init_val == nullptr) {24096 if (field->init_val == nullptr) {
23967 ir_add_error(ira, source_instr,24097 ir_add_error(ira, source_instr,
23968 buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));24098 buf_sprintf("missing field: '%s'", buf_ptr(field->name)));
23969 any_missing = true;24099 any_missing = true;
23970 continue;24100 continue;
23971 }24101 }
test/stage1/behavior/struct.zig+33
...@@ -851,3 +851,36 @@ test "struct with union field" {...@@ -851,3 +851,36 @@ test "struct with union field" {
851 expectEqual(@as(u32, 2), True.ref);851 expectEqual(@as(u32, 2), True.ref);
852 expectEqual(true, True.kind.Bool);852 expectEqual(true, True.kind.Bool);
853}853}
854
855test "type coercion of anon struct literal to struct" {
856 const S = struct {
857 const S2 = struct {
858 A: u32,
859 B: []const u8,
860 C: void,
861 D: Foo = .{},
862 };
863
864 const Foo = struct {
865 field: i32 = 1234,
866 };
867
868 fn doTheTest() void {
869 var y: u32 = 42;
870 const t0 = .{ .A = 123, .B = "foo", .C = {} };
871 const t1 = .{ .A = y, .B = "foo", .C = {} };
872 const y0: S2 = t0;
873 var y1: S2 = t1;
874 expect(y0.A == 123);
875 expect(std.mem.eql(u8, y0.B, "foo"));
876 expect(y0.C == {});
877 expect(y0.D.field == 1234);
878 expect(y1.A == y);
879 expect(std.mem.eql(u8, y1.B, "foo"));
880 expect(y1.C == {});
881 expect(y1.D.field == 1234);
882 }
883 };
884 S.doTheTest();
885 comptime S.doTheTest();
886}