From 5b279434986b18d07ceec217c5c402a589ccc0b4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Nov 2019 21:58:05 -0500 Subject: implement anon struct literal syntax This implements stage1 parser support for anonymous struct literal syntax (see #685), as well as semantic analysis support for anonymous struct literals and anonymous list literals (see #208). The semantic analysis works when there is a type coercion in the result location; inferring the struct type based on the values in the literal is not implemented yet. Also remaining to do is zig fmt support for this new syntax and documentation updates. --- src/ir.cpp | 204 ++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 129 insertions(+), 75 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 507b3e4459..f1b31af582 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1350,18 +1350,17 @@ static IrInstruction *ir_build_return_ptr(IrAnalyze *ira, IrInstruction *source_ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len, - IrInstruction *init_array_type) + AstNode *init_array_type_source_node) { IrInstructionElemPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->array_ptr = array_ptr; instruction->elem_index = elem_index; instruction->safety_check_on = safety_check_on; instruction->ptr_len = ptr_len; - instruction->init_array_type = init_array_type; + instruction->init_array_type_source_node = init_array_type_source_node; ir_ref_instruction(array_ptr, irb->current_basic_block); ir_ref_instruction(elem_index, irb->current_basic_block); - if (init_array_type != nullptr) ir_ref_instruction(init_array_type, irb->current_basic_block); return &instruction->base; } @@ -1575,17 +1574,16 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour } static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_type, size_t item_count, IrInstruction **elem_result_loc_list, - IrInstruction *result_loc) + size_t item_count, IrInstruction **elem_result_loc_list, IrInstruction *result_loc, + AstNode *init_array_type_source_node) { IrInstructionContainerInitList *container_init_list_instruction = ir_build_instruction(irb, scope, source_node); - container_init_list_instruction->container_type = container_type; container_init_list_instruction->item_count = item_count; container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; container_init_list_instruction->result_loc = result_loc; + container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; - ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < item_count; i += 1) { ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block); } @@ -1595,17 +1593,14 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, } static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields, - IrInstruction *result_loc) + size_t field_count, IrInstructionContainerInitFieldsField *fields, IrInstruction *result_loc) { IrInstructionContainerInitFields *container_init_fields_instruction = ir_build_instruction(irb, scope, source_node); - container_init_fields_instruction->container_type = container_type; container_init_fields_instruction->field_count = field_count; container_init_fields_instruction->fields = fields; container_init_fields_instruction->result_loc = result_loc; - ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < field_count; i += 1) { ir_ref_instruction(fields[i].result_loc, irb->current_basic_block); } @@ -3084,7 +3079,7 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN instruction->result_loc = result_loc; instruction->ty = ty; - ir_ref_instruction(ty, irb->current_basic_block); + if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block); return &instruction->base; } @@ -6127,28 +6122,42 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; ContainerInitKind kind = container_init_expr->kind; - IrInstruction *container_type = nullptr; - IrInstruction *elem_type = nullptr; - if (container_init_expr->type->type == NodeTypeInferredArrayType) { - elem_type = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.child_type, scope); - if (elem_type == irb->codegen->invalid_instruction) - return elem_type; - } else { - container_type = ir_gen_node(irb, container_init_expr->type, scope); - if (container_type == irb->codegen->invalid_instruction) - return container_type; - } - - switch (kind) { - case ContainerInitKindStruct: { - if (elem_type != nullptr) { + ResultLocCast *result_loc_cast = nullptr; + ResultLoc *child_result_loc; + AstNode *init_array_type_source_node; + if (container_init_expr->type != nullptr) { + IrInstruction *container_type; + if (container_init_expr->type->type == NodeTypeInferredArrayType) { + if (kind == ContainerInitKindStruct) { add_node_error(irb->codegen, container_init_expr->type, buf_sprintf("initializing array with struct syntax")); return irb->codegen->invalid_instruction; } + IrInstruction *elem_type = ir_gen_node(irb, + container_init_expr->type->data.inferred_array_type.child_type, scope); + if (elem_type == irb->codegen->invalid_instruction) + return elem_type; + size_t item_count = container_init_expr->entries.length; + IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); + container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); + } else { + container_type = ir_gen_node(irb, container_init_expr->type, scope); + if (container_type == irb->codegen->invalid_instruction) + return container_type; + } + + result_loc_cast = ir_build_cast_result_loc(irb, container_type, parent_result_loc); + child_result_loc = &result_loc_cast->base; + init_array_type_source_node = container_type->source_node; + } else { + child_result_loc = parent_result_loc; + init_array_type_source_node = parent_result_loc->source_instruction->source_node; + } - IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, - container_type); + switch (kind) { + case ContainerInitKindStruct: { + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, + nullptr); size_t field_count = container_init_expr->entries.length; IrInstructionContainerInitFieldsField *fields = allocate(field_count); @@ -6176,29 +6185,27 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A fields[i].source_node = entry_node; fields[i].result_loc = field_ptr; } - IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, - field_count, fields, container_ptr); + IrInstruction *result = ir_build_container_init_fields(irb, scope, node, field_count, + fields, container_ptr); - return ir_lval_wrap(irb, scope, init_fields, lval, parent_result_loc); + if (result_loc_cast != nullptr) { + result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); + } + return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); } case ContainerInitKindArray: { size_t item_count = container_init_expr->entries.length; - if (container_type == nullptr) { - IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); - container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); - } - - IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, - container_type); + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, + nullptr); IrInstruction **result_locs = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); IrInstruction *elem_index = ir_build_const_usize(irb, scope, expr_node, i); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, elem_index, - false, PtrLenSingle, container_type); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, + elem_index, false, PtrLenSingle, init_array_type_source_node); ResultLocInstruction *result_loc_inst = allocate(1); result_loc_inst->base.id = ResultLocIdInstruction; result_loc_inst->base.source_instruction = elem_ptr; @@ -6213,9 +6220,12 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A result_locs[i] = elem_ptr; } - IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, - item_count, result_locs, container_ptr); - return ir_lval_wrap(irb, scope, init_list, lval, parent_result_loc); + IrInstruction *result = ir_build_container_init_list(irb, scope, node, item_count, + result_locs, container_ptr, init_array_type_source_node); + if (result_loc_cast != nullptr) { + result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); + } + return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); } } zig_unreachable(); @@ -7935,14 +7945,14 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char *kind_name, Scope *scope, AstNode *source_node, Buf *out_bare_name) { - if (exec->name) { + if (exec != nullptr && exec->name) { ZigType *import = get_scope_import(scope); Buf *namespace_name = buf_alloc(); append_namespace_qualification(codegen, namespace_name, import); buf_append_buf(namespace_name, exec->name); buf_init_from_buf(out_bare_name, exec->name); return namespace_name; - } else if (exec->name_fn != nullptr) { + } else if (exec != nullptr && exec->name_fn != nullptr) { Buf *name = buf_alloc(); buf_append_buf(name, &exec->name_fn->symbol_name); buf_appendf(name, "("); @@ -15541,11 +15551,7 @@ static bool ir_result_has_type(ResultLoc *result_loc) { static IrInstruction *ir_resolve_no_result_loc(IrAnalyze *ira, IrInstruction *suspend_source_instr, ResultLoc *result_loc, ZigType *value_type, bool force_runtime, bool non_null_comptime) { - Error err; - IrInstructionAllocaGen *alloca_gen = ir_build_alloca_gen(ira, suspend_source_instr, 0, ""); - if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_instruction; alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false, PtrLenSingle, 0, 0, 0, false); set_up_result_loc_for_inferred_comptime(&alloca_gen->base); @@ -15750,6 +15756,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return casted_value; } + bool old_parent_result_loc_written = result_cast->parent->written; IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_cast->parent, dest_type, casted_value, force_runtime, non_null_comptime, true); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || @@ -15775,6 +15782,22 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); + { + // we also need to check that this cast is OK. + ConstCastOnly const_cast_result = types_match_const_cast_only(ira, + parent_result_loc->value.type, ptr_type, + result_cast->base.source_instruction->source_node, false); + if (const_cast_result.id == ConstCastResultIdInvalid) + return ira->codegen->invalid_instruction; + if (const_cast_result.id != ConstCastResultIdOk) { + // We will not be able to provide a result location for this value. Create + // a new result location. + result_cast->parent->written = old_parent_result_loc_written; + return ir_resolve_no_result_loc(ira, suspend_source_instr, result_loc, value_type, + force_runtime, non_null_comptime); + } + } + result_loc->written = true; result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, ptr_type, result_cast->base.source_instruction, false); @@ -15902,10 +15925,33 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return result_loc; } -static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { - ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(implicit_elem_type)) - return ira->codegen->invalid_instruction; +static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, + IrInstructionResolveResult *instruction) +{ + ZigType *implicit_elem_type; + if (instruction->ty == nullptr) { + if (instruction->result_loc->id == ResultLocIdCast) { + implicit_elem_type = ir_resolve_type(ira, + instruction->result_loc->source_instruction->child); + if (type_is_invalid(implicit_elem_type)) + return ira->codegen->invalid_instruction; + } else { + Buf *bare_name = buf_alloc(); + Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), + instruction->base.scope, instruction->base.source_node, bare_name); + + ZigType *inferred_struct_type = get_partial_container_type(ira->codegen, + instruction->base.scope, ContainerKindStruct, instruction->base.source_node, + buf_ptr(name), bare_name, ContainerLayoutAuto); + inferred_struct_type->data.structure.is_inferred = true; + inferred_struct_type->data.structure.resolve_status = ResolveStatusBeingInferred; + implicit_elem_type = inferred_struct_type; + } + } else { + implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(implicit_elem_type)) + return ira->codegen->invalid_instruction; + } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr, false, true, true); if (result_loc != nullptr) @@ -17837,7 +17883,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct if (array_ptr_val == nullptr) return ira->codegen->invalid_instruction; - if (array_ptr_val->special == ConstValSpecialUndef && elem_ptr_instruction->init_array_type != nullptr) { + if (array_ptr_val->special == ConstValSpecialUndef && + elem_ptr_instruction->init_array_type_source_node != nullptr) + { if (array_type->id == ZigTypeIdArray || array_type->id == ZigTypeIdVector) { array_ptr_val->data.x_array.special = ConstArraySpecialNone; array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len); @@ -17851,11 +17899,13 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct elem_val->parent.data.p_array.elem_index = i; } } else if (is_slice(array_type)) { - ZigType *actual_array_type = ir_resolve_type(ira, elem_ptr_instruction->init_array_type->child); + ir_assert(array_ptr->value.type->id == ZigTypeIdPointer, &elem_ptr_instruction->base); + ZigType *actual_array_type = array_ptr->value.type->data.pointer.child_type; + if (type_is_invalid(actual_array_type)) return ira->codegen->invalid_instruction; if (actual_array_type->id != ZigTypeIdArray) { - ir_add_error(ira, elem_ptr_instruction->init_array_type, + ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, buf_sprintf("expected array type or [_], found slice")); return ira->codegen->invalid_instruction; } @@ -17879,7 +17929,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct false); array_ptr_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = ConstPtrMutInfer; } else { - ir_add_error(ira, elem_ptr_instruction->init_array_type, + ir_add_error_node(ira, elem_ptr_instruction->init_array_type_source_node, buf_sprintf("expected array type or [_], found '%s'", buf_ptr(&array_type->name))); return ira->codegen->invalid_instruction; @@ -18012,7 +18062,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, - false, elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); + false, elem_ptr_instruction->ptr_len, nullptr); result->value.type = return_type; result->value.special = ConstValSpecialStatic; } else { @@ -18073,7 +18123,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on, - elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); + elem_ptr_instruction->ptr_len, nullptr); result->value.type = return_type; return result; } @@ -18223,6 +18273,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ Error err; ZigType *bare_type = container_ref_type(container_type); + if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20124,14 +20175,18 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { - ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; + ir_assert(instruction->result_loc != nullptr, &instruction->base); + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return result_loc; + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); + + ZigType *container_type = result_loc->value.type->data.pointer.child_type; size_t elem_count = instruction->item_count; if (is_slice(container_type)) { - ir_add_error(ira, instruction->container_type, + ir_add_error_node(ira, instruction->init_array_type_source_node, buf_sprintf("expected array type or [_], found slice")); return ira->codegen->invalid_instruction; } @@ -20160,12 +20215,6 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - ir_assert(instruction->result_loc != nullptr, &instruction->base); - IrInstruction *result_loc = instruction->result_loc->child; - if (type_is_invalid(result_loc->value.type)) - return result_loc; - ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); - ZigType *child_type = container_type->data.array.child_type; if (container_type->data.array.len != elem_count) { ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); @@ -20262,16 +20311,14 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { - IrInstruction *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; - ir_assert(instruction->result_loc != nullptr, &instruction->base); IrInstruction *result_loc = instruction->result_loc->child; if (type_is_invalid(result_loc->value.type)) return result_loc; + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); + ZigType *container_type = result_loc->value.type->data.pointer.child_type; + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, instruction->field_count, instruction->fields, result_loc); } @@ -24607,6 +24654,10 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *src_type = ptr->value.type; assert(!type_is_invalid(src_type)); + if (src_type == dest_type) { + return ptr; + } + // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. @@ -24656,6 +24707,9 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ IrInstruction *result; if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) { result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); + + if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; } else { result = ir_const(ira, source_instr, dest_type); } -- cgit v1.2.3 From 1bca8e693d42256d575c76fbab5c68d86c0c4bc3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Nov 2019 13:18:16 -0500 Subject: fix anon literal used with return result loc --- src/ir.cpp | 10 +++++++++- test/stage1/behavior/union.zig | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index f1b31af582..e278193785 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6151,7 +6151,11 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A init_array_type_source_node = container_type->source_node; } else { child_result_loc = parent_result_loc; - init_array_type_source_node = parent_result_loc->source_instruction->source_node; + if (parent_result_loc->source_instruction != nullptr) { + init_array_type_source_node = parent_result_loc->source_instruction->source_node; + } else { + init_array_type_source_node = node; + } } switch (kind) { @@ -15935,6 +15939,10 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, instruction->result_loc->source_instruction->child); if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; + } else if (instruction->result_loc->id == ResultLocIdReturn) { + implicit_elem_type = ira->explicit_return_type; + if (type_is_invalid(implicit_elem_type)) + return ira->codegen->invalid_instruction; } else { Buf *bare_name = buf_alloc(); Buf *name = get_anon_type_name(ira->codegen, nullptr, container_string(ContainerKindStruct), diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index de98a26d55..caad1d474f 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -559,10 +559,14 @@ test "anonymous union literal syntax" { fn doTheTest() void { var i: Number = .{.int = 42}; - var f: Number = .{.float = 12.34}; + var f = makeNumber(); expect(i.int == 42); expect(f.float == 12.34); } + + fn makeNumber() Number { + return .{.float = 12.34}; + } }; S.doTheTest(); comptime S.doTheTest(); -- cgit v1.2.3 From ca2a788a240bbc3fa8060471bcda845e543dac70 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Nov 2019 17:50:41 -0500 Subject: fully anonymous struct literals --- src/all_types.hpp | 13 ++++ src/analyze.cpp | 133 ++++++++++++++++++++++---------- src/analyze.hpp | 3 +- src/ir.cpp | 163 ++++++++++++++++++++++++++++++++++------ test/stage1/behavior/struct.zig | 22 ++++++ 5 files changed, 271 insertions(+), 63 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 4d751bae2c..e38e857209 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1187,10 +1187,22 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); static const uint32_t VECTOR_INDEX_NONE = UINT32_MAX; static const uint32_t VECTOR_INDEX_RUNTIME = UINT32_MAX - 1; +struct InferredStructField { + ZigType *inferred_struct_type; + Buf *field_name; +}; + struct ZigTypePointer { ZigType *child_type; ZigType *slice_parent; + // Anonymous struct literal syntax uses this when the result location has + // no type in it. This field is null if this pointer does not refer to + // a field of a currently-being-inferred struct type. + // When this is non-null, the pointer is pointing to the base of the inferred + // struct. + InferredStructField *inferred_struct_field; + PtrLen ptr_len; uint32_t explicit_alignment; // 0 means use ABI alignment @@ -1743,6 +1755,7 @@ struct TypeId { union { struct { ZigType *child_type; + InferredStructField *inferred_struct_field; PtrLen ptr_len; uint32_t alignment; diff --git a/src/analyze.cpp b/src/analyze.cpp index ae5b626c29..d8ff4f2848 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -486,7 +486,7 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, - uint32_t vector_index) + uint32_t vector_index, InferredStructField *inferred_struct_field) { assert(ptr_len != PtrLenC || allow_zero); assert(!type_is_invalid(child_type)); @@ -509,7 +509,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con TypeId type_id = {}; ZigType **parent_pointer = nullptr; if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || - allow_zero || vector_index != VECTOR_INDEX_NONE) + allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; @@ -521,6 +521,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con type_id.data.pointer.ptr_len = ptr_len; type_id.data.pointer.allow_zero = allow_zero; type_id.data.pointer.vector_index = vector_index; + type_id.data.pointer.inferred_struct_field = inferred_struct_field; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -548,8 +549,15 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con } buf_resize(&entry->name, 0); if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) { - buf_appendf(&entry->name, "%s%s%s%s%s", - star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); + if (inferred_struct_field == nullptr) { + buf_appendf(&entry->name, "%s%s%s%s%s", + star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); + } else { + buf_appendf(&entry->name, "(%s%s%s%s field '%s' of %s)", + star_str, const_str, volatile_str, allow_zero_str, + buf_ptr(inferred_struct_field->field_name), + buf_ptr(&inferred_struct_field->inferred_struct_type->name)); + } } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) { buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); @@ -606,6 +614,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con entry->data.pointer.host_int_bytes = host_int_bytes; entry->data.pointer.allow_zero = allow_zero; entry->data.pointer.vector_index = vector_index; + entry->data.pointer.inferred_struct_field = inferred_struct_field; if (parent_pointer) { *parent_pointer = entry; @@ -620,12 +629,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) { return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, - byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE); + byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr); } ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, - VECTOR_INDEX_NONE); + VECTOR_INDEX_NONE, nullptr); } ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { @@ -2082,7 +2091,7 @@ 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); + assert(decl_node->type == NodeTypeContainerDecl || decl_node->type == NodeTypeContainerInitExpr); size_t field_count = struct_type->data.structure.src_field_count; @@ -2670,7 +2679,6 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { return ErrorNone; AstNode *decl_node = struct_type->data.structure.decl_node; - assert(decl_node->type == NodeTypeContainerDecl); if (struct_type->data.structure.resolve_loop_flag_zero_bits) { if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { @@ -2681,29 +2689,46 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { } return ErrorSemanticAnalyzeFail; } - struct_type->data.structure.resolve_loop_flag_zero_bits = true; - assert(!struct_type->data.structure.fields); - size_t field_count = decl_node->data.container_decl.fields.length; - struct_type->data.structure.src_field_count = (uint32_t)field_count; - struct_type->data.structure.fields = allocate(field_count); + size_t field_count; + if (decl_node->type == NodeTypeContainerDecl) { + field_count = decl_node->data.container_decl.fields.length; + struct_type->data.structure.src_field_count = (uint32_t)field_count; + + src_assert(struct_type->data.structure.fields == nullptr, decl_node); + struct_type->data.structure.fields = allocate(field_count); + } else if (decl_node->type == NodeTypeContainerInitExpr) { + src_assert(struct_type->data.structure.is_inferred, decl_node); + src_assert(struct_type->data.structure.fields != nullptr, decl_node); + + field_count = struct_type->data.structure.src_field_count; + } else zig_unreachable(); + struct_type->data.structure.fields_by_name.init(field_count); Scope *scope = &struct_type->data.structure.decls_scope->base; size_t gen_field_index = 0; for (size_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; - type_struct_field->name = field_node->data.struct_field.name; - type_struct_field->decl_node = field_node; - if (field_node->data.struct_field.type == nullptr) { - add_node_error(g, field_node, buf_sprintf("struct field missing type")); - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } + AstNode *field_node; + if (decl_node->type == NodeTypeContainerDecl) { + field_node = decl_node->data.container_decl.fields.at(i); + type_struct_field->name = field_node->data.struct_field.name; + type_struct_field->decl_node = field_node; + + if (field_node->data.struct_field.type == nullptr) { + add_node_error(g, field_node, buf_sprintf("struct field missing type")); + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + } else if (decl_node->type == NodeTypeContainerInitExpr) { + field_node = type_struct_field->decl_node; + + src_assert(type_struct_field->type_entry != nullptr, field_node); + } else zig_unreachable(); auto field_entry = struct_type->data.structure.fields_by_name.put_unique(type_struct_field->name, type_struct_field); if (field_entry != nullptr) { @@ -2714,16 +2739,21 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { return ErrorSemanticAnalyzeFail; } - ConstExprValue *field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - type_struct_field->type_val = field_type_val; - if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; + ConstExprValue *field_type_val; + if (decl_node->type == NodeTypeContainerDecl) { + field_type_val = analyze_const_value(g, scope, + field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); + if (type_is_invalid(field_type_val->type)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + assert(field_type_val->special != ConstValSpecialRuntime); + type_struct_field->type_val = field_type_val; + if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; + } else if (decl_node->type == NodeTypeContainerInitExpr) { + field_type_val = type_struct_field->type_val; + } else zig_unreachable(); bool field_is_opaque_type; if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { @@ -2807,7 +2837,7 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { } struct_type->data.structure.resolve_loop_flag_other = true; - assert(decl_node->type == NodeTypeContainerDecl); + 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; @@ -2817,7 +2847,8 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { if (field->gen_index == SIZE_MAX) continue; - AstNode *align_expr = field->decl_node->data.struct_field.align_expr; + AstNode *align_expr = (field->decl_node->type == NodeTypeStructField) ? + field->decl_node->data.struct_field.align_expr : nullptr; if (align_expr != nullptr) { if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, &field->align)) @@ -5416,6 +5447,12 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { if (type_entry->one_possible_value != OnePossibleValueInvalid) return type_entry->one_possible_value; + if (type_entry->id == ZigTypeIdStruct && + type_entry->data.structure.resolve_status == ResolveStatusBeingInferred) + { + return OnePossibleValueNo; + } + Error err; if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) return OnePossibleValueInvalid; @@ -5820,9 +5857,15 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ ConstExprValue *create_const_vals(size_t count) { - ConstGlobalRefs *global_refs = allocate(count, "ConstGlobalRefs"); - ConstExprValue *vals = allocate(count, "ConstExprValue"); - for (size_t i = 0; i < count; i += 1) { + return realloc_const_vals(nullptr, 0, count); +} + +ConstExprValue *realloc_const_vals(ConstExprValue *base, size_t old_count, size_t new_count) { + ConstGlobalRefs *old_global_refs = (base == nullptr) ? nullptr : base->global_refs; + ConstGlobalRefs *global_refs = reallocate(old_global_refs, old_count, + new_count, "ConstGlobalRefs"); + ConstExprValue *vals = reallocate(base, old_count, new_count, "ConstExprValue"); + for (size_t i = old_count; i < new_count; i += 1) { vals[i].global_refs = &global_refs[i]; } return vals; @@ -7002,7 +7045,16 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.vector_index == b.data.pointer.vector_index && - a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; + a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes && + ( + a.data.pointer.inferred_struct_field == b.data.pointer.inferred_struct_field || + (a.data.pointer.inferred_struct_field != nullptr && + b.data.pointer.inferred_struct_field != nullptr && + a.data.pointer.inferred_struct_field->inferred_struct_type == + b.data.pointer.inferred_struct_field->inferred_struct_type && + buf_eql_buf(a.data.pointer.inferred_struct_field->field_name, + b.data.pointer.inferred_struct_field->field_name)) + ); case ZigTypeIdArray: return a.data.array.child_type == b.data.array.child_type && a.data.array.size == b.data.array.size; @@ -7815,7 +7867,6 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS ZigLLVMDIScope *di_scope; unsigned line; if (decl_node != nullptr) { - assert(decl_node->type == NodeTypeContainerDecl); Scope *scope = &struct_type->data.structure.decls_scope->base; ZigType *import = get_scope_import(scope); di_file = import->data.structure.root_struct->di_file; @@ -8018,7 +8069,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS } unsigned line; if (decl_node != nullptr) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); + AstNode *field_node = field->decl_node; line = field_node->line + 1; } else { line = 0; @@ -8314,12 +8365,12 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, - VECTOR_INDEX_NONE); + VECTOR_INDEX_NONE, nullptr); } else { uint32_t host_vec_len = type->data.pointer.host_int_bytes; ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE); + PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr); } type->llvm_type = get_llvm_type(g, peer_type); type->llvm_di_type = get_llvm_di_type(g, peer_type); diff --git a/src/analyze.hpp b/src/analyze.hpp index a6af371e25..7de51092e8 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -24,7 +24,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero, uint32_t vector_index); + bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field); uint64_t type_size(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); @@ -175,6 +175,7 @@ void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_inde ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); ConstExprValue *create_const_vals(size_t count); +ConstExprValue *realloc_const_vals(ConstExprValue *base, size_t old_count, size_t new_count); ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); void expand_undef_array(CodeGen *g, ConstExprValue *const_val); diff --git a/src/ir.cpp b/src/ir.cpp index e278193785..fb2b0ed841 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -202,6 +202,8 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char Scope *scope, AstNode *source_node, Buf *out_bare_name); static ResultLocCast *ir_build_cast_result_loc(IrBuilder *irb, IrInstruction *dest_type, ResultLoc *parent_result_loc); +static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, + TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -16321,13 +16323,81 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return ir_const_void(ira, source_instr); } - ZigType *child_type = ptr->value.type->data.pointer.child_type; + InferredStructField *isf = ptr->value.type->data.pointer.inferred_struct_field; + if (allow_write_through_const && isf != nullptr) { + // Now it's time to add the field to the struct type. + uint32_t old_field_count = isf->inferred_struct_type->data.structure.src_field_count; + uint32_t new_field_count = old_field_count + 1; + isf->inferred_struct_type->data.structure.src_field_count = new_field_count; + // This thing with max(x, 16) is a hack to allow this functionality to work without + // modifying the ConstExprValue layout of structs. That reworking needs to be + // done, but this hack lets us do it separately, in the future. + TypeStructField *prev_ptr = isf->inferred_struct_type->data.structure.fields; + isf->inferred_struct_type->data.structure.fields = reallocate( + isf->inferred_struct_type->data.structure.fields, + (old_field_count == 0) ? 0 : max(old_field_count, 16u), + max(new_field_count, 16u)); + if (prev_ptr != nullptr && prev_ptr != isf->inferred_struct_type->data.structure.fields) { + zig_panic("TODO need to rework the layout of ZigTypeStruct. this realloc would have caused invalid pointer references"); + } + + // This reference can't live long, don't keep it around outside this block. + TypeStructField *field = &isf->inferred_struct_type->data.structure.fields[old_field_count]; + field->name = isf->field_name; + field->type_entry = uncasted_value->value.type; + field->type_val = create_const_type(ira->codegen, field->type_entry); + field->src_index = old_field_count; + field->decl_node = uncasted_value->source_node; + + ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false); + IrInstruction *casted_ptr; + if (instr_is_comptime(ptr)) { + casted_ptr = ir_const(ira, source_instr, struct_ptr_type); + copy_const_val(&casted_ptr->value, &ptr->value, false); + casted_ptr->value.type = struct_ptr_type; + } else { + casted_ptr = ir_build_cast(&ira->new_irb, source_instr->scope, + source_instr->source_node, struct_ptr_type, ptr, CastOpNoop); + casted_ptr->value.type = struct_ptr_type; + } + if (instr_is_comptime(casted_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, + source_instr->source_node); + struct_val->special = ConstValSpecialStatic; + ConstExprValue *prev_ptr = struct_val->data.x_struct.fields; + // This thing with max(x, 16) is a hack to allow this functionality to work without + // modifying the ConstExprValue layout of structs. That reworking needs to be + // done, but this hack lets us do it separately, in the future. + struct_val->data.x_struct.fields = realloc_const_vals(struct_val->data.x_struct.fields, + (old_field_count == 0) ? 0 : max(old_field_count, 16u), + max(new_field_count, 16u)); + if (prev_ptr != nullptr && prev_ptr != struct_val->data.x_struct.fields) { + zig_panic("TODO need to rework the layout of ConstExprValue for structs. this realloc would have caused invalid pointer references"); + } + + ConstExprValue *field_val = &struct_val->data.x_struct.fields[old_field_count]; + field_val->special = ConstValSpecialUndef; + field_val->type = field->type_entry; + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = struct_val; + field_val->parent.data.p_struct.field_index = old_field_count; + } + } + + ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, casted_ptr, + isf->inferred_struct_type, true); + } if (ptr->value.type->data.pointer.is_const && !allow_write_through_const) { ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); return ira->codegen->invalid_instruction; } + ZigType *child_type = ptr->value.type->data.pointer.child_type; IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type); if (value == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; @@ -17853,7 +17923,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index); + get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, + nullptr); } else if (return_type->data.pointer.explicit_alignment != 0) { // figure out the largest alignment possible @@ -18094,7 +18165,8 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct return_type = get_pointer_to_type_extra2(ira->codegen, elem_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, elem_ptr_instruction->ptr_len, - get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME); + get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME, + nullptr); } else { // runtime known element index switch (type_requires_comptime(ira->codegen, return_type)) { @@ -18210,31 +18282,34 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction case OnePossibleValueNo: break; } - ResolveStatus needed_resolve_status = - (struct_type->data.structure.layout == ContainerLayoutAuto) ? - ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; - if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) - return ira->codegen->invalid_instruction; - assert(struct_ptr->value.type->id == ZigTypeIdPointer); - uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; - uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; - uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? - get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; bool is_const = struct_ptr->value.type->data.pointer.is_const; bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, field->align, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - (uint32_t)host_int_bytes_for_result_type, false); + ZigType *ptr_type; + if (struct_type->data.structure.is_inferred) { + ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, + is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); + } else { + ResolveStatus needed_resolve_status = + (struct_type->data.structure.layout == ContainerLayoutAuto) ? + ResolveStatusZeroBitsKnown : ResolveStatusSizeKnown; + if ((err = type_resolve(ira->codegen, struct_type, needed_resolve_status))) + return ira->codegen->invalid_instruction; + assert(struct_ptr->value.type->id == ZigTypeIdPointer); + uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; + uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; + uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? + get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; + ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, + is_const, is_volatile, PtrLenSingle, field->align, + (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), + (uint32_t)host_int_bytes_for_result_type, false); + } if (instr_is_comptime(struct_ptr)) { ConstExprValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (struct_val == nullptr) return ira->codegen->invalid_instruction; @@ -18246,7 +18321,8 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; field_val->special = ConstValSpecialUndef; - field_val->type = struct_type->data.structure.fields[i].type_entry; + field_val->type = resolve_struct_field_type(ira->codegen, + &struct_type->data.structure.fields[i]); field_val->parent.id = ConstParentIdStruct; field_val->parent.data.p_struct.struct_val = struct_val; field_val->parent.data.p_struct.field_index = i; @@ -18275,6 +18351,40 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction return result; } +static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type) +{ + // The type of the field is not available until a store using this pointer happens. + // So, here we create a special pointer type which has the inferred struct type and + // field name encoded in the type. Later, when there is a store via this pointer, + // the field type will then be available, and the field will be added to the inferred + // struct. + + ZigType *container_ptr_type = container_ptr->value.type; + ir_assert(container_ptr_type->id == ZigTypeIdPointer, source_instr); + + InferredStructField *inferred_struct_field = allocate(1, "InferredStructField"); + inferred_struct_field->inferred_struct_type = container_type; + inferred_struct_field->field_name = field_name; + + ZigType *elem_type = ira->codegen->builtin_types.entry_c_void; + ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, + container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, + PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field); + + if (instr_is_comptime(container_ptr)) { + IrInstruction *result = ir_const(ira, source_instr, field_ptr_type); + copy_const_val(&result->value, &container_ptr->value, false); + result->value.type = field_ptr_type; + return result; + } + + IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, + source_instr->source_node, field_ptr_type, container_ptr, CastOpNoop); + result->value.type = field_ptr_type; + return result; +} + static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { @@ -18282,6 +18392,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ ZigType *bare_type = container_ref_type(container_type); + if (initializing && bare_type->id == ZigTypeIdStruct && + bare_type->data.structure.resolve_status == ResolveStatusBeingInferred) + { + return ir_analyze_inferred_field_ptr(ira, field_name, source_instr, container_ptr, bare_type); + } + if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; @@ -20056,6 +20172,11 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } + if (container_type->data.structure.resolve_status == ResolveStatusBeingInferred) { + // We're now done inferring the type. + container_type->data.structure.resolve_status = ResolveStatusUnstarted; + } + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 571343e281..6b9ddacabc 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -729,3 +729,25 @@ test "anonymous struct literal syntax" { S.doTheTest(); comptime S.doTheTest(); } + +test "fully anonymous struct" { + const S = struct { + fn doTheTest() void { + dump(.{ + .int = @as(u32, 1234), + .float = @as(f64, 12.34), + .b = true, + .s = "hi", + }); + } + fn dump(args: var) void { + expect(args.int == 1234); + expect(args.float == 12.34); + expect(args.b); + expect(args.s[0] == 'h'); + expect(args.s[1] == 'i'); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3 From b9482fc32d13886626692484e5a778355fa7934c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Nov 2019 19:00:39 -0500 Subject: implement fully anonymous list literals --- src/analyze.cpp | 12 ++---- src/analyze.hpp | 1 - src/ir.cpp | 85 +++++++++++++++++++++++++---------------- test/stage1/behavior/struct.zig | 17 +++++++++ 4 files changed, 73 insertions(+), 42 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index d8ff4f2848..316fa52ac5 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5857,15 +5857,9 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ ConstExprValue *create_const_vals(size_t count) { - return realloc_const_vals(nullptr, 0, count); -} - -ConstExprValue *realloc_const_vals(ConstExprValue *base, size_t old_count, size_t new_count) { - ConstGlobalRefs *old_global_refs = (base == nullptr) ? nullptr : base->global_refs; - ConstGlobalRefs *global_refs = reallocate(old_global_refs, old_count, - new_count, "ConstGlobalRefs"); - ConstExprValue *vals = reallocate(base, old_count, new_count, "ConstExprValue"); - for (size_t i = old_count; i < new_count; i += 1) { + ConstGlobalRefs *global_refs = allocate(count, "ConstGlobalRefs"); + ConstExprValue *vals = allocate(count, "ConstExprValue"); + for (size_t i = 0; i < count; i += 1) { vals[i].global_refs = &global_refs[i]; } return vals; diff --git a/src/analyze.hpp b/src/analyze.hpp index 7de51092e8..06c8847eda 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -175,7 +175,6 @@ void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_inde ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); ConstExprValue *create_const_vals(size_t count); -ConstExprValue *realloc_const_vals(ConstExprValue *base, size_t old_count, size_t new_count); ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); void expand_undef_array(CodeGen *g, ConstExprValue *const_val); diff --git a/src/ir.cpp b/src/ir.cpp index fb2b0ed841..9d15e341da 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -204,6 +204,8 @@ static ResultLocCast *ir_build_cast_result_loc(IrBuilder *irb, IrInstruction *de ResultLoc *parent_result_loc); static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing); +static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -16329,16 +16331,14 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source uint32_t old_field_count = isf->inferred_struct_type->data.structure.src_field_count; uint32_t new_field_count = old_field_count + 1; isf->inferred_struct_type->data.structure.src_field_count = new_field_count; - // This thing with max(x, 16) is a hack to allow this functionality to work without - // modifying the ConstExprValue layout of structs. That reworking needs to be - // done, but this hack lets us do it separately, in the future. - TypeStructField *prev_ptr = isf->inferred_struct_type->data.structure.fields; - isf->inferred_struct_type->data.structure.fields = reallocate( - isf->inferred_struct_type->data.structure.fields, - (old_field_count == 0) ? 0 : max(old_field_count, 16u), - max(new_field_count, 16u)); - if (prev_ptr != nullptr && prev_ptr != isf->inferred_struct_type->data.structure.fields) { - zig_panic("TODO need to rework the layout of ZigTypeStruct. this realloc would have caused invalid pointer references"); + if (new_field_count > 16) { + // This thing with 16 is a hack to allow this functionality to work without + // modifying the ConstExprValue layout of structs. That reworking needs to be + // done, but this hack lets us do it separately, in the future. + zig_panic("TODO need to rework the layout of ZigTypeStruct. This realloc would have caused invalid pointer references"); + } + if (isf->inferred_struct_type->data.structure.fields == nullptr) { + isf->inferred_struct_type->data.structure.fields = allocate(16); } // This reference can't live long, don't keep it around outside this block. @@ -16368,15 +16368,14 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); struct_val->special = ConstValSpecialStatic; - ConstExprValue *prev_ptr = struct_val->data.x_struct.fields; - // This thing with max(x, 16) is a hack to allow this functionality to work without - // modifying the ConstExprValue layout of structs. That reworking needs to be - // done, but this hack lets us do it separately, in the future. - struct_val->data.x_struct.fields = realloc_const_vals(struct_val->data.x_struct.fields, - (old_field_count == 0) ? 0 : max(old_field_count, 16u), - max(new_field_count, 16u)); - if (prev_ptr != nullptr && prev_ptr != struct_val->data.x_struct.fields) { - zig_panic("TODO need to rework the layout of ConstExprValue for structs. this realloc would have caused invalid pointer references"); + if (new_field_count > 16) { + // This thing with 16 is a hack to allow this functionality to work without + // modifying the ConstExprValue layout of structs. That reworking needs to be + // done, but this hack lets us do it separately, in the future. + zig_panic("TODO need to rework the layout of ConstExprValue for structs. This realloc would have caused invalid pointer references"); + } + if (struct_val->data.x_struct.fields == nullptr) { + struct_val->data.x_struct.fields = create_const_vals(16); } ConstExprValue *field_val = &struct_val->data.x_struct.fields[old_field_count]; @@ -17893,6 +17892,19 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } else if (array_type->id == ZigTypeIdVector) { // This depends on whether the element index is comptime, so it is computed later. return_type = nullptr; + } else if (elem_ptr_instruction->init_array_type_source_node != nullptr && + array_type->id == ZigTypeIdStruct && + array_type->data.structure.resolve_status == ResolveStatusBeingInferred) + { + ZigType *usize = ira->codegen->builtin_types.entry_usize; + IrInstruction *casted_elem_index = ir_implicit_cast(ira, elem_index, usize); + if (casted_elem_index == ira->codegen->invalid_instruction) + return ira->codegen->invalid_instruction; + ir_assert(instr_is_comptime(casted_elem_index), &elem_ptr_instruction->base); + Buf *field_name = buf_alloc(); + bigint_append_buf(field_name, &casted_elem_index->value.data.x_bigint, 10); + return ir_analyze_inferred_field_ptr(ira, field_name, &elem_ptr_instruction->base, + array_ptr, array_type); } else { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); @@ -20246,8 +20258,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc TypeStructField *field = &container_type->data.structure.fields[i]; if (field->init_val == nullptr) { // it's not memoized. time to go analyze it - assert(field->decl_node->type == NodeTypeStructField); - AstNode *init_node = field->decl_node->data.struct_field.value; + AstNode *init_node; + if (field->decl_node->type == NodeTypeStructField) { + init_node = field->decl_node->data.struct_field.value; + } else { + init_node = nullptr; + } if (init_node == nullptr) { ir_add_error_node(ira, instruction->source_node, buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); @@ -20337,23 +20353,28 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc); } - if (container_type->id != ZigTypeIdArray) { + if (container_type->id == ZigTypeIdArray) { + ZigType *child_type = container_type->data.array.child_type; + if (container_type->data.array.len != elem_count) { + ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); + + ir_add_error(ira, &instruction->base, + buf_sprintf("expected %s literal, found %s literal", + buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); + return ira->codegen->invalid_instruction; + } + } else if (container_type->id == ZigTypeIdStruct && + container_type->data.structure.resolve_status == ResolveStatusBeingInferred) + { + // We're now done inferring the type. + container_type->data.structure.resolve_status = ResolveStatusUnstarted; + } else { ir_add_error_node(ira, instruction->base.source_node, buf_sprintf("type '%s' does not support array initialization", buf_ptr(&container_type->name))); return ira->codegen->invalid_instruction; } - ZigType *child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); - - ir_add_error(ira, &instruction->base, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_instruction; - } - switch (type_has_one_possible_value(ira->codegen, container_type)) { case OnePossibleValueInvalid: return ira->codegen->invalid_instruction; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 6b9ddacabc..a42c261e3b 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -751,3 +751,20 @@ test "fully anonymous struct" { S.doTheTest(); comptime S.doTheTest(); } + +test "fully anonymous list literal" { + const S = struct { + fn doTheTest() void { + dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"}); + } + fn dump(args: var) void { + expect(args.@"0" == 1234); + expect(args.@"1" == 12.34); + expect(args.@"2"); + expect(args.@"3"[0] == 'h'); + expect(args.@"3"[1] == 'i'); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} -- cgit v1.2.3