From 5874cb04bd544ca155d1489bb0bdf9397fa3b41c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 8 Dec 2019 22:44:41 -0500 Subject: [PATCH] implement tuple concatenation --- src/analyze.cpp | 9 +-- src/ir.cpp | 113 ++++++++++++++++++++++++++++++++- test/stage1/behavior.zig | 1 + test/stage1/behavior/tuple.zig | 18 ++++++ 4 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 test/stage1/behavior/tuple.zig diff --git a/src/analyze.cpp b/src/analyze.cpp index 1f253ac157..fefa5352da 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2142,7 +2142,6 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { } assert(struct_type->data.structure.fields || struct_type->data.structure.src_field_count == 0); - assert(decl_node->type == NodeTypeContainerDecl || decl_node->type == NodeTypeContainerInitExpr); size_t field_count = struct_type->data.structure.src_field_count; @@ -2749,10 +2748,9 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { src_assert(struct_type->data.structure.fields == nullptr, decl_node); struct_type->data.structure.fields = alloc_type_struct_fields(field_count); - } else if (decl_node->type == NodeTypeContainerInitExpr) { + } else if (is_anon_container(struct_type)) { field_count = struct_type->data.structure.src_field_count; - src_assert(is_anon_container(struct_type), decl_node); src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node); } else zig_unreachable(); @@ -2785,7 +2783,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - } else if (decl_node->type == NodeTypeContainerInitExpr) { + } else if (is_anon_container(struct_type)) { field_node = type_struct_field->decl_node; src_assert(type_struct_field->type_entry != nullptr, field_node); @@ -2812,7 +2810,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { type_struct_field->type_val = field_type_val; if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) return ErrorSemanticAnalyzeFail; - } else if (decl_node->type == NodeTypeContainerInitExpr) { + } else if (is_anon_container(struct_type)) { field_type_val = type_struct_field->type_val; } else zig_unreachable(); @@ -2901,7 +2899,6 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } struct_type->data.structure.resolve_loop_flag_other = true; - assert(decl_node->type == NodeTypeContainerDecl || decl_node->type == NodeTypeContainerInitExpr); size_t field_count = struct_type->data.structure.src_field_count; bool packed = struct_type->data.structure.layout == ContainerLayoutPacked; diff --git a/src/ir.cpp b/src/ir.cpp index fc53e2ecdf..09e0b70928 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15573,6 +15573,110 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return result; } +static IrInstruction *ir_analyze_tuple_cat(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *op1, IrInstruction *op2) +{ + Error err; + ZigType *op1_type = op1->value->type; + ZigType *op2_type = op2->value->type; + + uint32_t op1_field_count = op1_type->data.structure.src_field_count; + uint32_t op2_field_count = op2_type->data.structure.src_field_count; + + Buf *bare_name = buf_alloc(); + Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), + source_instr->scope, source_instr->source_node, bare_name); + ZigType *new_type = get_partial_container_type(ira->codegen, source_instr->scope, + ContainerKindStruct, source_instr->source_node, buf_ptr(name), bare_name, ContainerLayoutAuto); + new_type->data.structure.special = StructSpecialInferredTuple; + new_type->data.structure.resolve_status = ResolveStatusBeingInferred; + + bool is_comptime = ir_should_inline(ira->new_irb.exec, source_instr->scope); + + IrInstruction *new_struct_ptr = ir_resolve_result(ira, source_instr, no_result_loc(), + new_type, nullptr, false, false, true); + uint32_t new_field_count = op1_field_count + op2_field_count; + + new_type->data.structure.src_field_count = new_field_count; + new_type->data.structure.fields = realloc_type_struct_fields(new_type->data.structure.fields, + 0, new_field_count); + for (uint32_t i = 0; i < new_field_count; i += 1) { + TypeStructField *src_field; + if (i < op1_field_count) { + src_field = op1_type->data.structure.fields[i]; + } else { + src_field = op2_type->data.structure.fields[i - op1_field_count]; + } + TypeStructField *new_field = new_type->data.structure.fields[i]; + new_field->name = buf_sprintf("%" PRIu32, i); + new_field->type_entry = src_field->type_entry; + new_field->type_val = src_field->type_val; + new_field->src_index = i; + new_field->decl_node = src_field->decl_node; + new_field->init_val = src_field->init_val; + new_field->is_comptime = src_field->is_comptime; + } + if ((err = type_resolve(ira->codegen, new_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + + ZigList const_ptrs = {}; + IrInstruction *first_non_const_instruction = nullptr; + for (uint32_t i = 0; i < new_field_count; i += 1) { + TypeStructField *dst_field = new_type->data.structure.fields[i]; + IrInstruction *src_struct_op; + TypeStructField *src_field; + if (i < op1_field_count) { + src_field = op1_type->data.structure.fields[i]; + src_struct_op = op1; + } else { + src_field = op2_type->data.structure.fields[i - op1_field_count]; + src_struct_op = op2; + } + IrInstruction *field_value = ir_analyze_struct_value_field_value(ira, source_instr, + src_struct_op, src_field); + if (type_is_invalid(field_value->value->type)) + return ira->codegen->invalid_instruction; + IrInstruction *dest_ptr = ir_analyze_struct_field_ptr(ira, source_instr, dst_field, + new_struct_ptr, new_type, true); + if (type_is_invalid(dest_ptr->value->type)) + return ira->codegen->invalid_instruction; + if (instr_is_comptime(field_value)) { + const_ptrs.append(dest_ptr); + } else { + first_non_const_instruction = field_value; + } + IrInstruction *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, dest_ptr, field_value, + true); + if (type_is_invalid(store_ptr_inst->value->type)) + return ira->codegen->invalid_instruction; + } + if (const_ptrs.length != new_field_count) { + new_struct_ptr->value->special = ConstValSpecialRuntime; + for (size_t i = 0; i < const_ptrs.length; i += 1) { + IrInstruction *elem_result_loc = const_ptrs.at(i); + assert(elem_result_loc->value->special == ConstValSpecialStatic); + if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) { + // This field will be generated comptime; no need to do this. + continue; + } + IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr); + elem_result_loc->value->special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref, false); + } + } + IrInstruction *result = ir_get_deref(ira, source_instr, new_struct_ptr, nullptr); + if (instr_is_comptime(result)) + return result; + + if (is_comptime) { + ir_add_error_node(ira, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->invalid_instruction; + } + + return result; +} + static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *instruction) { IrInstruction *op1 = instruction->op1->child; ZigType *op1_type = op1->value->type; @@ -15584,6 +15688,10 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i if (type_is_invalid(op2_type)) return ira->codegen->invalid_instruction; + if (is_tuple(op1_type) && is_tuple(op2_type)) { + return ir_analyze_tuple_cat(ira, &instruction->base, op1, op2); + } + ZigValue *op1_val = ir_resolve_const(ira, op1, UndefBad); if (!op1_val) return ira->codegen->invalid_instruction; @@ -17446,11 +17554,12 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source } if (instr_is_comptime(ptr) && ptr->value->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if (ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) { + if (!allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) { ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); return ira->codegen->invalid_instruction; } - if (ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar || + if ((allow_write_through_const && ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst) || + ptr->value->data.x_ptr.mut == ConstPtrMutComptimeVar || ptr->value->data.x_ptr.mut == ConstPtrMutInfer) { if (instr_is_comptime(value)) { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index ecbb46fae0..ea8720d98c 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -103,6 +103,7 @@ comptime { _ = @import("behavior/this.zig"); _ = @import("behavior/truncate.zig"); _ = @import("behavior/try.zig"); + _ = @import("behavior/tuple.zig"); _ = @import("behavior/type.zig"); _ = @import("behavior/type_info.zig"); _ = @import("behavior/typename.zig"); diff --git a/test/stage1/behavior/tuple.zig b/test/stage1/behavior/tuple.zig new file mode 100644 index 0000000000..13d3d05681 --- /dev/null +++ b/test/stage1/behavior/tuple.zig @@ -0,0 +1,18 @@ +const std = @import("std"); +const expect = std.testing.expect; + +test "tuple concatenation" { + const S = struct { + fn doTheTest() void { + var a: i32 = 1; + var b: i32 = 2; + var x = .{a}; + var y = .{b}; + var c = x ++ y; + expect(c[0] == 1); + expect(c[1] == 2); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +}