parent
e7207bc267
commit
2bb3e1aff4
146
src/ir.cpp
146
src/ir.cpp
|
@ -286,6 +286,7 @@ static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* so
|
|||
IrInstGen *struct_operand, TypeStructField *field);
|
||||
static bool value_cmp_numeric_val_any(ZigValue *left, Cmp predicate, ZigValue *right);
|
||||
static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *right);
|
||||
static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field);
|
||||
|
||||
#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__)
|
||||
#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
|
|||
}
|
||||
|
||||
static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* source_instr,
|
||||
IrInstGen *value, ZigType *wanted_type)
|
||||
IrInstGen *struct_operand, ZigType *wanted_type)
|
||||
{
|
||||
ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to struct"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
Error err;
|
||||
|
||||
IrInstGen *struct_ptr = ir_get_ref(ira, source_instr, struct_operand, true, false);
|
||||
if (type_is_invalid(struct_ptr->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
if (wanted_type->data.structure.resolve_status == ResolveStatusBeingInferred) {
|
||||
ir_add_error(ira, source_instr, buf_sprintf("type coercion of anon struct literal to inferred struct"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
size_t actual_field_count = wanted_type->data.structure.src_field_count;
|
||||
size_t instr_field_count = struct_operand->value->type->data.structure.src_field_count;
|
||||
|
||||
bool need_comptime = ir_should_inline(ira->old_irb.exec, source_instr->scope)
|
||||
|| type_requires_comptime(ira->codegen, wanted_type) == ReqCompTimeYes;
|
||||
bool is_comptime = true;
|
||||
|
||||
// Determine if the struct_operand will be comptime.
|
||||
// Also emit compile errors for missing fields and duplicate fields.
|
||||
AstNode **field_assign_nodes = heap::c_allocator.allocate<AstNode *>(actual_field_count);
|
||||
ZigValue **field_values = heap::c_allocator.allocate<ZigValue *>(actual_field_count);
|
||||
IrInstGen **casted_fields = heap::c_allocator.allocate<IrInstGen *>(actual_field_count);
|
||||
IrInstGen *const_result = ir_const(ira, source_instr, wanted_type);
|
||||
|
||||
for (size_t i = 0; i < instr_field_count; i += 1) {
|
||||
TypeStructField *src_field = struct_operand->value->type->data.structure.fields[i];
|
||||
TypeStructField *dst_field = find_struct_type_field(wanted_type, src_field->name);
|
||||
if (dst_field == nullptr) {
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("no field named '%s' in struct '%s'",
|
||||
buf_ptr(src_field->name), buf_ptr(&wanted_type->name)));
|
||||
if (wanted_type->data.structure.decl_node) {
|
||||
add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node,
|
||||
buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name)));
|
||||
}
|
||||
add_error_note(ira->codegen, msg, src_field->decl_node,
|
||||
buf_sprintf("field '%s' declared here", buf_ptr(src_field->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
ir_assert(src_field->decl_node != nullptr, source_instr);
|
||||
AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index];
|
||||
if (existing_assign_node != nullptr) {
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("duplicate field"));
|
||||
add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here"));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
field_assign_nodes[dst_field->src_index] = src_field->decl_node;
|
||||
|
||||
IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, src_field, struct_ptr,
|
||||
struct_operand->value->type, false);
|
||||
if (type_is_invalid(field_ptr->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
IrInstGen *field_value = ir_get_deref(ira, source_instr, field_ptr, nullptr);
|
||||
if (type_is_invalid(field_value->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
IrInstGen *casted_value = ir_implicit_cast(ira, field_value, dst_field->type_entry);
|
||||
if (type_is_invalid(casted_value->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
casted_fields[dst_field->src_index] = casted_value;
|
||||
if (need_comptime || instr_is_comptime(casted_value)) {
|
||||
ZigValue *field_val = ir_resolve_const(ira, casted_value, UndefOk);
|
||||
if (field_val == nullptr)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
field_val->parent.id = ConstParentIdStruct;
|
||||
field_val->parent.data.p_struct.struct_val = const_result->value;
|
||||
field_val->parent.data.p_struct.field_index = dst_field->src_index;
|
||||
field_values[dst_field->src_index] = field_val;
|
||||
} else {
|
||||
is_comptime = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool any_missing = false;
|
||||
for (size_t i = 0; i < actual_field_count; i += 1) {
|
||||
if (field_assign_nodes[i] != nullptr) continue;
|
||||
|
||||
// look for a default field value
|
||||
TypeStructField *field = wanted_type->data.structure.fields[i];
|
||||
memoize_field_init_val(ira->codegen, wanted_type, field);
|
||||
if (field->init_val == nullptr) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("missing field: '%s'", buf_ptr(field->name)));
|
||||
any_missing = true;
|
||||
continue;
|
||||
}
|
||||
if (type_is_invalid(field->init_val->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
ZigValue *init_val_copy = ira->codegen->pass1_arena->create<ZigValue>();
|
||||
copy_const_val(ira->codegen, init_val_copy, field->init_val);
|
||||
init_val_copy->parent.id = ConstParentIdStruct;
|
||||
init_val_copy->parent.data.p_struct.struct_val = const_result->value;
|
||||
init_val_copy->parent.data.p_struct.field_index = i;
|
||||
field_values[i] = init_val_copy;
|
||||
casted_fields[i] = ir_const_move(ira, source_instr, init_val_copy);
|
||||
}
|
||||
if (any_missing)
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
|
||||
if (is_comptime) {
|
||||
heap::c_allocator.deallocate(field_assign_nodes, actual_field_count);
|
||||
IrInstGen *const_result = ir_const(ira, source_instr, wanted_type);
|
||||
const_result->value->data.x_struct.fields = field_values;
|
||||
return const_result;
|
||||
}
|
||||
|
||||
IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(),
|
||||
wanted_type, nullptr, true, true);
|
||||
if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) {
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < actual_field_count; i += 1) {
|
||||
TypeStructField *field = wanted_type->data.structure.fields[i];
|
||||
IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, result_loc_inst, wanted_type, true);
|
||||
if (type_is_invalid(field_ptr->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, field_ptr, casted_fields[i], true);
|
||||
if (type_is_invalid(store_ptr_inst->value->type))
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
||||
heap::c_allocator.deallocate(field_assign_nodes, actual_field_count);
|
||||
heap::c_allocator.deallocate(field_values, actual_field_count);
|
||||
heap::c_allocator.deallocate(casted_fields, actual_field_count);
|
||||
|
||||
return ir_get_deref(ira, source_instr, result_loc_inst, nullptr);
|
||||
}
|
||||
|
||||
static 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
|
|||
TypeUnionField *union_field = find_union_type_field(union_type, only_field->name);
|
||||
if (union_field == nullptr) {
|
||||
ir_add_error_node(ira, only_field->decl_node,
|
||||
buf_sprintf("no member named '%s' in union '%s'",
|
||||
buf_sprintf("no field named '%s' in union '%s'",
|
||||
buf_ptr(only_field->name), buf_ptr(&union_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
@ -22407,7 +22537,7 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel
|
|||
usize, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
|
||||
} else {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
|
||||
buf_sprintf("no field named '%s' in '%s'", buf_ptr(field_name),
|
||||
buf_ptr(&container_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
@ -23834,7 +23964,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi
|
|||
TypeUnionField *type_field = find_union_type_field(union_type, field_name);
|
||||
if (type_field == nullptr) {
|
||||
ir_add_error_node(ira, field_source_node,
|
||||
buf_sprintf("no member named '%s' in union '%s'",
|
||||
buf_sprintf("no field named '%s' in union '%s'",
|
||||
buf_ptr(field_name), buf_ptr(&union_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
@ -23930,7 +24060,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
|
|||
TypeStructField *type_field = find_struct_type_field(container_type, field->name);
|
||||
if (!type_field) {
|
||||
ir_add_error_node(ira, field->source_node,
|
||||
buf_sprintf("no member named '%s' in struct '%s'",
|
||||
buf_sprintf("no field named '%s' in struct '%s'",
|
||||
buf_ptr(field->name), buf_ptr(&container_type->name)));
|
||||
return ira->codegen->invalid_inst_gen;
|
||||
}
|
||||
|
@ -23965,7 +24095,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
|
|||
memoize_field_init_val(ira->codegen, container_type, field);
|
||||
if (field->init_val == nullptr) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
|
||||
buf_sprintf("missing field: '%s'", buf_ptr(field->name)));
|
||||
any_missing = true;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -851,3 +851,36 @@ test "struct with union field" {
|
|||
expectEqual(@as(u32, 2), True.ref);
|
||||
expectEqual(true, True.kind.Bool);
|
||||
}
|
||||
|
||||
test "type coercion of anon struct literal to struct" {
|
||||
const S = struct {
|
||||
const S2 = struct {
|
||||
A: u32,
|
||||
B: []const u8,
|
||||
C: void,
|
||||
D: Foo = .{},
|
||||
};
|
||||
|
||||
const Foo = struct {
|
||||
field: i32 = 1234,
|
||||
};
|
||||
|
||||
fn doTheTest() void {
|
||||
var y: u32 = 42;
|
||||
const t0 = .{ .A = 123, .B = "foo", .C = {} };
|
||||
const t1 = .{ .A = y, .B = "foo", .C = {} };
|
||||
const y0: S2 = t0;
|
||||
var y1: S2 = t1;
|
||||
expect(y0.A == 123);
|
||||
expect(std.mem.eql(u8, y0.B, "foo"));
|
||||
expect(y0.C == {});
|
||||
expect(y0.D.field == 1234);
|
||||
expect(y1.A == y);
|
||||
expect(std.mem.eql(u8, y1.B, "foo"));
|
||||
expect(y1.C == {});
|
||||
expect(y1.D.field == 1234);
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue