Commit b980568c81

Andrew Kelley <andrew@ziglang.org>
2020-03-30 19:01:53
add peer type resolution for mixed-const []T and *[N]T
closes #4766 This commit also fixes the implementation of some utility functions for adjusting properties of pointer types. Previously these functions would incorrectly drop vector, sentinel, and inference metadata.
1 parent ef419dd
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -231,6 +231,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op);
 static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc);
 static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc);
 static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
+static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const);
 static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
 static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val);
 static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val);
@@ -11844,6 +11845,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
 
     bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull);
     bool convert_to_const_slice = false;
+    bool make_the_slice_const = false;
     for (; i < instruction_count; i += 1) {
         IrInstGen *cur_inst = instructions[i];
         ZigType *cur_type = cur_inst->value->type;
@@ -12357,12 +12359,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
             ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ?
                 prev_type->data.error_union.payload_type : prev_type;
             ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
-            if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
-                        !cur_type->data.pointer.is_const) &&
-                types_match_const_cast_only(ira,
-                    slice_ptr_type->data.pointer.child_type,
+            if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
                     array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
             {
+                bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
+                        !cur_type->data.pointer.is_const);
+                if (!const_ok) make_the_slice_const = true;
                 convert_to_const_slice = false;
                 continue;
             }
@@ -12391,12 +12393,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                     break;
             }
             ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
-            if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
-                        !prev_type->data.pointer.is_const) &&
-                types_match_const_cast_only(ira,
-                    slice_ptr_type->data.pointer.child_type,
+            if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
                     array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
             {
+                bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 ||
+                        !prev_type->data.pointer.is_const);
+                if (!const_ok) make_the_slice_const = true;
                 prev_inst = cur_inst;
                 convert_to_const_slice = false;
                 continue;
@@ -12408,8 +12410,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                 cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
             prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle &&
                 prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
-            (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
-                prev_type->data.pointer.child_type->data.array.len == 0) &&
             (
                 prev_type->data.pointer.child_type->data.array.sentinel == nullptr ||
                 (cur_type->data.pointer.child_type->data.array.sentinel != nullptr &&
@@ -12421,6 +12421,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                 prev_type->data.pointer.child_type->data.array.child_type,
                 source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk)
         {
+            bool const_ok = (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const ||
+                prev_type->data.pointer.child_type->data.array.len == 0);
+            if (!const_ok) make_the_slice_const = true;
             prev_inst = cur_inst;
             convert_to_const_slice = true;
             continue;
@@ -12429,8 +12432,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                 prev_type->data.pointer.child_type->id == ZigTypeIdArray &&
             cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle &&
                 cur_type->data.pointer.child_type->id == ZigTypeIdArray &&
-            (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
-                cur_type->data.pointer.child_type->data.array.len == 0) &&
             (
                 cur_type->data.pointer.child_type->data.array.sentinel == nullptr ||
                 (prev_type->data.pointer.child_type->data.array.sentinel != nullptr &&
@@ -12442,6 +12443,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                 cur_type->data.pointer.child_type->data.array.child_type,
                 source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk)
         {
+            bool const_ok = (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const ||
+                cur_type->data.pointer.child_type->data.array.len == 0);
+            if (!const_ok) make_the_slice_const = true;
             convert_to_const_slice = true;
             continue;
         }
@@ -12486,7 +12490,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
             src_assert(array_type->id == ZigTypeIdArray, source_node);
             ZigType *ptr_type = get_pointer_to_type_extra2(
                     ira->codegen, array_type->data.array.child_type,
-                    prev_inst->value->type->data.pointer.is_const, false,
+                    prev_inst->value->type->data.pointer.is_const || make_the_slice_const, false,
                     PtrLenUnknown,
                     0, 0, 0, false,
                     VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel);
@@ -12537,6 +12541,26 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
                 return ira->codegen->builtin_types.entry_invalid;
             return get_optional_type(ira->codegen, prev_inst->value->type);
         }
+    } else if (make_the_slice_const) {
+        ZigType *slice_type;
+        if (prev_inst->value->type->id == ZigTypeIdErrorUnion) {
+            slice_type = prev_inst->value->type->data.error_union.payload_type;
+        } else if (is_slice(prev_inst->value->type)) {
+            slice_type = prev_inst->value->type;
+        } else {
+            zig_unreachable();
+        }
+        ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry;
+        ZigType *adjusted_ptr_type = adjust_ptr_const(ira->codegen, slice_ptr_type, make_the_slice_const);
+        ZigType *adjusted_slice_type = get_slice_type(ira->codegen, adjusted_ptr_type);
+        if (prev_inst->value->type->id == ZigTypeIdErrorUnion) {
+            return get_error_union_type(ira->codegen, prev_inst->value->type->data.error_union.err_set_type,
+                    adjusted_slice_type);
+        } else if (is_slice(prev_inst->value->type)) {
+            return adjusted_slice_type;
+        } else {
+            zig_unreachable();
+        }
     } else {
         return prev_inst->value->type;
     }
@@ -20708,24 +20732,44 @@ static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new
 
 static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
     assert(ptr_type->id == ZigTypeIdPointer);
-    return get_pointer_to_type_extra(g,
+    return get_pointer_to_type_extra2(g,
             ptr_type->data.pointer.child_type,
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
             ptr_len,
             ptr_type->data.pointer.explicit_alignment,
             ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
-            ptr_type->data.pointer.allow_zero);
+            ptr_type->data.pointer.allow_zero,
+            ptr_type->data.pointer.vector_index,
+            ptr_type->data.pointer.inferred_struct_field,
+            ptr_type->data.pointer.sentinel);
 }
 
 static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) {
     assert(ptr_type->id == ZigTypeIdPointer);
-    return get_pointer_to_type_extra(g,
+    return get_pointer_to_type_extra2(g,
             ptr_type->data.pointer.child_type,
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
             ptr_type->data.pointer.ptr_len,
             ptr_type->data.pointer.explicit_alignment,
             ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
-            allow_zero);
+            allow_zero,
+            ptr_type->data.pointer.vector_index,
+            ptr_type->data.pointer.inferred_struct_field,
+            ptr_type->data.pointer.sentinel);
+}
+
+static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const) {
+    assert(ptr_type->id == ZigTypeIdPointer);
+    return get_pointer_to_type_extra2(g,
+            ptr_type->data.pointer.child_type,
+            is_const, ptr_type->data.pointer.is_volatile,
+            ptr_type->data.pointer.ptr_len,
+            ptr_type->data.pointer.explicit_alignment,
+            ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
+            ptr_type->data.pointer.allow_zero,
+            ptr_type->data.pointer.vector_index,
+            ptr_type->data.pointer.inferred_struct_field,
+            ptr_type->data.pointer.sentinel);
 }
 
 static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align,
test/stage1/behavior/cast.zig
@@ -790,3 +790,18 @@ test "assignment to optional pointer result loc" {
     var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct };
     expect(foo.ptr.? == @ptrCast(*c_void, &global_struct));
 }
+
+test "peer type resolve string lit with sentinel-terminated mutable slice" {
+    var array: [4:0]u8 = undefined;
+    array[4] = 0; // TODO remove this when #4372 is solved
+    var slice: [:0]u8 = array[0..4 :0];
+    comptime expect(@TypeOf(slice, "hi") == [:0]const u8);
+    comptime expect(@TypeOf("hi", slice) == [:0]const u8);
+}
+
+test "peer type resolve array pointers, one of them const" {
+    var array1: [4]u8 = undefined;
+    const array2: [5]u8 = undefined;
+    comptime expect(@TypeOf(&array1, &array2) == []const u8);
+    comptime expect(@TypeOf(&array2, &array1) == []const u8);
+}