From debcc79d56a40f77b92e243b4e344fc9385bd405 Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Thu, 5 Mar 2020 19:23:06 +0200 Subject: [PATCH] Allow constant struct val to reallocate its fields when resolving an inferred struct field with a comptime value. --- src/ir.cpp | 33 ++++++++++++++++++++-------- test/stage1/behavior/tuple.zig | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 56ba634189..517c07147d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -18477,6 +18477,15 @@ static IrInstGen *ir_resolve_result(IrAnalyze *ira, IrInst *suspend_source_instr IrInstGen *casted_ptr; if (isf->already_resolved) { field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); + + // If the value originates from another node than the original value's we overwrite the inferred struct's + // type so that the new result can be written successfully. + // The duplicate field will be detected and reported in 'ir_analyze_container_init_fields' + AstNode *decl_node = value ? value->base.source_node : suspend_source_instr->source_node; + if (decl_node != field->decl_node) { + field->type_entry = value_type; + field->type_val = create_const_type(ira->codegen, field->type_entry); + } casted_ptr = result_loc; } else { isf->already_resolved = true; @@ -18493,15 +18502,6 @@ static IrInstGen *ir_resolve_result(IrAnalyze *ira, IrInst *suspend_source_instr field->type_val = create_const_type(ira->codegen, field->type_entry); field->src_index = old_field_count; field->decl_node = value ? value->base.source_node : suspend_source_instr->source_node; - if (value && instr_is_comptime(value)) { - ZigValue *val = ir_resolve_const(ira, value, UndefOk); - if (!val) - return ira->codegen->invalid_inst_gen; - field->is_comptime = true; - field->init_val = ira->codegen->pass1_arena->create(); - copy_const_val(ira->codegen, field->init_val, val); - return result_loc; - } ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false); if (instr_is_comptime(result_loc)) { @@ -18532,6 +18532,16 @@ static IrInstGen *ir_resolve_result(IrAnalyze *ira, IrInst *suspend_source_instr } } + if (value && instr_is_comptime(value)) { + ZigValue *val = ir_resolve_const(ira, value, UndefOk); + if (!val) + return ira->codegen->invalid_inst_gen; + field->is_comptime = true; + field->init_val = ira->codegen->pass1_arena->create(); + copy_const_val(ira->codegen, field->init_val, val); + return result_loc; + } + result_loc = ir_analyze_struct_field_ptr(ira, suspend_source_instr, field, casted_ptr, isf->inferred_struct_type, true); result_loc_pass1->resolved_loc = result_loc; @@ -22957,6 +22967,9 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc first_non_const_instruction = result_loc; } } + + heap::c_allocator.deallocate(field_assign_nodes, actual_field_count); + if (any_missing) return ira->codegen->invalid_inst_gen; @@ -22972,6 +22985,8 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc } } + const_ptrs.deinit(); + IrInstGen *result = ir_get_deref(ira, source_instr, result_loc, nullptr); if (is_comptime && !instr_is_comptime(result)) { diff --git a/test/stage1/behavior/tuple.zig b/test/stage1/behavior/tuple.zig index 686a9ad83e..e18af349dd 100644 --- a/test/stage1/behavior/tuple.zig +++ b/test/stage1/behavior/tuple.zig @@ -54,3 +54,42 @@ test "tuple concatenation" { T.doTheTest(); comptime T.doTheTest(); } + +test "tuple initialization with structure initializer and constant expression" { + const TestStruct = struct { + state: u8, + }; + + const S = struct { + fn doTheTest() void { + const tuple_with_struct = .{ TestStruct{ .state = 42 }, 0 }; + expect(tuple_with_struct.len == 2); + expect(tuple_with_struct[0].state == 42); + expect(tuple_with_struct[1] == 0); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "passing tuples as comptime generic parameters" { + const S = struct { + fn expect_len(comptime pack: var, comptime len: usize) void { + expect(pack.len == len); + } + + fn expect_first_element(comptime pack: var, comptime elem: var) void { + expect(pack[0] == elem); + } + + fn doTheTest() void { + expect_len(.{}, 0); + expect_len(.{ 0 }, 1); + expect_first_element(.{ 0 }, 0); + expect_len(.{ u8, 1, "literal" }, 3); + expect_first_element(.{ u8, 1, "literal" }, u8); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +}