Commit 4e182c7e9e

Andrew Kelley <andrew@ziglang.org>
2019-06-17 23:46:03
inferred comptime array inits
1 parent 0568000
Changed files (3)
src/all_types.hpp
@@ -2640,7 +2640,7 @@ struct IrInstructionContainerInitList {
     IrInstruction *container_type;
     IrInstruction *elem_type;
     size_t item_count;
-    IrInstruction **items;
+    IrInstruction **elem_result_loc_list;
     IrInstruction *result_loc;
 };
 
src/ir.cpp
@@ -1524,18 +1524,19 @@ 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 **items, IrInstruction *result_loc)
+        IrInstruction *container_type, size_t item_count, IrInstruction **elem_result_loc_list,
+        IrInstruction *result_loc)
 {
     IrInstructionContainerInitList *container_init_list_instruction =
         ir_build_instruction<IrInstructionContainerInitList>(irb, scope, source_node);
     container_init_list_instruction->container_type = container_type;
     container_init_list_instruction->item_count = item_count;
-    container_init_list_instruction->items = items;
+    container_init_list_instruction->elem_result_loc_list = elem_result_loc_list;
     container_init_list_instruction->result_loc = result_loc;
 
     ir_ref_instruction(container_type, irb->current_basic_block);
     for (size_t i = 0; i < item_count; i += 1) {
-        ir_ref_instruction(items[i], irb->current_basic_block);
+        ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block);
     }
     if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
 
@@ -5802,7 +5803,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
             IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc,
                     container_type);
 
-            IrInstruction **values = allocate<IrInstruction *>(item_count);
+            IrInstruction **result_locs = allocate<IrInstruction *>(item_count);
             for (size_t i = 0; i < item_count; i += 1) {
                 AstNode *expr_node = container_init_expr->entries.at(i);
 
@@ -5813,16 +5814,17 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
                 result_loc_inst->base.id = ResultLocIdInstruction;
                 result_loc_inst->base.source_instruction = elem_ptr;
                 ir_ref_instruction(elem_ptr, irb->current_basic_block);
+                ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base);
 
                 IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone,
                         &result_loc_inst->base);
                 if (expr_value == irb->codegen->invalid_instruction)
                     return expr_value;
 
-                values[i] = expr_value;
+                result_locs[i] = elem_ptr;
             }
             IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type,
-                    item_count, values, container_ptr);
+                    item_count, result_locs, container_ptr);
             return ir_lval_wrap(irb, scope, init_list, lval, parent_result_loc);
         }
     }
@@ -16891,6 +16893,22 @@ 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 && array_type->id == ZigTypeIdArray &&
+                elem_ptr_instruction->initializing)
+            {
+                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);
+                array_ptr_val->special = ConstValSpecialStatic;
+                for (size_t i = 0; i < array_type->data.array.len; i += 1) {
+                    ConstExprValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i];
+                    elem_val->special = ConstValSpecialUndef;
+                    elem_val->type = array_type->data.array.child_type;
+                    elem_val->parent.id = ConstParentIdArray;
+                    elem_val->parent.data.p_array.array_val = array_ptr_val;
+                    elem_val->parent.data.p_array.elem_index = i;
+                }
+            }
+
             if (array_ptr_val->special != ConstValSpecialRuntime &&
                 (array_type->id != ZigTypeIdPointer ||
                     array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
@@ -17011,7 +17029,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                     }
                     return result;
                 } else if (array_type->id == ZigTypeIdArray) {
-                    IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+                    IrInstruction *result;
+                    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->initializing);
+                        result->value.type = return_type;
+                        result->value.special = ConstValSpecialStatic;
+                    } else {
+                        result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+                    }
                     ConstExprValue *out_val = &result->value;
                     out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
                     out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
@@ -19099,8 +19126,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
 static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
         IrInstructionContainerInitList *instruction)
 {
-    Error err;
-
     ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child);
     if (type_is_invalid(container_type))
         return ira->codegen->invalid_instruction;
@@ -19111,125 +19136,122 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
         ir_add_error(ira, &instruction->base,
             buf_sprintf("expected array type or [_], found slice"));
         return ira->codegen->invalid_instruction;
-    } else if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
+    }
+
+    if (container_type->id == ZigTypeIdVoid) {
+        if (elem_count != 0) {
+            ir_add_error_node(ira, instruction->base.source_node,
+                buf_sprintf("void expression expects no arguments"));
+            return ira->codegen->invalid_instruction;
+        }
+        return ir_const_void(ira, &instruction->base);
+    }
+
+    if (container_type->id == ZigTypeIdStruct && elem_count == 0) {
         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;
         return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc);
-    } else if (container_type->id == ZigTypeIdArray) {
-        // array is same as slice init but we make a compile error if the length is wrong
-        ZigType *child_type;
-        if (container_type->id == ZigTypeIdArray) {
-            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 {
-            ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
-            assert(pointer_type->id == ZigTypeIdPointer);
-            child_type = pointer_type->data.pointer.child_type;
-        }
-
-        if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) {
-            return ira->codegen->invalid_instruction;
-        }
+    }
 
-        ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+    if (container_type->id != ZigTypeIdArray) {
+        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;
+    }
 
-        ConstExprValue const_val = {};
-        const_val.special = ConstValSpecialStatic;
-        const_val.type = fixed_size_array_type;
-        // const_val.global_refs = allocate<ConstGlobalRefs>(1);
-        const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
+    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);
 
-        bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+    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);
 
-        IrInstruction **new_items = allocate<IrInstruction *>(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;
+    }
 
-        IrInstruction *first_non_const_instruction = nullptr;
+    bool is_comptime;
+    switch (type_requires_comptime(ira->codegen, container_type)) {
+        case ReqCompTimeInvalid:
+            return ira->codegen->invalid_instruction;
+        case ReqCompTimeNo:
+            is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+            break;
+        case ReqCompTimeYes:
+            is_comptime = true;
+            break;
+    }
 
-        for (size_t i = 0; i < elem_count; i += 1) {
-            IrInstruction *arg_value = instruction->items[i]->child;
-            if (type_is_invalid(arg_value->value.type))
-                return ira->codegen->invalid_instruction;
+    IrInstruction *first_non_const_instruction = nullptr;
 
-            IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
-            if (casted_arg == ira->codegen->invalid_instruction)
-                return ira->codegen->invalid_instruction;
+    // The Result Location Mechanism has already emitted runtime instructions to
+    // initialize runtime elements and has omitted instructions for the comptime
+    // elements. However it is only now that we find out whether the array initialization
+    // can be a comptime value. So we must clean up the situation. If it turns out
+    // array initialization can be a comptime value, overwrite ConstPtrMutInfer with
+    // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the
+    // elements that have comptime-known values.
+    ZigList<IrInstruction *> const_ptrs = {};
 
-            new_items[i] = casted_arg;
+    for (size_t i = 0; i < elem_count; i += 1) {
+        IrInstruction *elem_result_loc = instruction->elem_result_loc_list[i]->child;
+        if (type_is_invalid(elem_result_loc->value.type))
+            return ira->codegen->invalid_instruction;
 
-            if (const_val.special == ConstValSpecialStatic) {
-                if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
-                    ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
-                    if (!elem_val)
-                        return ira->codegen->invalid_instruction;
+        assert(elem_result_loc->value.type->id == ZigTypeIdPointer);
 
-                    copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
-                } else {
-                    first_non_const_instruction = casted_arg;
-                    const_val.special = ConstValSpecialRuntime;
-                }
-            }
+        if (instr_is_comptime(elem_result_loc) &&
+            elem_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+        {
+            const_ptrs.append(elem_result_loc);
+        } else {
+            first_non_const_instruction = elem_result_loc;
         }
+    }
 
-        if (const_val.special == ConstValSpecialStatic) {
-            IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
-            ConstExprValue *out_val = &result->value;
-            copy_const_val(out_val, &const_val, false);
-            result->value.type = fixed_size_array_type;
-            for (size_t i = 0; i < elem_count; i += 1) {
-                ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
-                ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
-                if (parent != nullptr) {
-                    parent->id = ConstParentIdArray;
-                    parent->data.p_array.array_val = out_val;
-                    parent->data.p_array.elem_index = i;
-                }
+    if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+        if (const_ptrs.length == elem_count) {
+            result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+        } else {
+            result_loc->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);
+                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);
             }
-            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;
-        }
+    IrInstruction *result = ir_get_deref(ira, &instruction->base, result_loc, nullptr);
+    if (instr_is_comptime(result))
+        return result;
 
-        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 *result_elem_type = result_loc->value.type->data.pointer.child_type;
-        if (is_slice(result_elem_type)) {
-            ErrorMsg *msg = ir_add_error(ira, &instruction->base,
-                buf_sprintf("runtime-initialized array cannot be casted to slice type '%s'",
-                    buf_ptr(&result_elem_type->name)));
-            add_error_note(ira->codegen, msg, first_non_const_instruction->source_node,
-                buf_sprintf("this value is not comptime-known"));
-            return ira->codegen->invalid_instruction;
-        }
-        return ir_get_deref(ira, &instruction->base, result_loc, nullptr);
-    } else if (container_type->id == ZigTypeIdVoid) {
-        if (elem_count != 0) {
-            ir_add_error_node(ira, instruction->base.source_node,
-                buf_sprintf("void expression expects no arguments"));
-            return ira->codegen->invalid_instruction;
-        }
-        return ir_const_void(ira, &instruction->base);
-    } else {
-        ir_add_error_node(ira, instruction->base.source_node,
-            buf_sprintf("type '%s' does not support array initialization",
-                buf_ptr(&container_type->name)));
+    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;
+    }
+
+    ZigType *result_elem_type = result_loc->value.type->data.pointer.child_type;
+    if (is_slice(result_elem_type)) {
+        ErrorMsg *msg = ir_add_error(ira, &instruction->base,
+            buf_sprintf("runtime-initialized array cannot be casted to slice type '%s'",
+                buf_ptr(&result_elem_type->name)));
+        add_error_note(ira->codegen, msg, first_non_const_instruction->source_node,
+            buf_sprintf("this value is not comptime-known"));
         return ira->codegen->invalid_instruction;
     }
+    return result;
 }
 
 static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
src/ir_print.cpp
@@ -348,10 +348,10 @@ static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerIni
         fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count);
     } else {
         for (size_t i = 0; i < instruction->item_count; i += 1) {
-            IrInstruction *item = instruction->items[i];
+            IrInstruction *result_loc = instruction->elem_result_loc_list[i];
             if (i != 0)
                 fprintf(irp->f, ", ");
-            ir_print_other_instruction(irp, item);
+            ir_print_other_instruction(irp, result_loc);
         }
     }
     fprintf(irp->f, "}");