Commit 65c0475970

Mitchell Hashimoto <mitchell.hashimoto@gmail.com>
2022-02-22 22:34:51
stage2: peer type resolution *[N]T and *[M]T to []const T
1 parent ffb7ac6
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -16858,6 +16858,8 @@ fn resolvePeerTypes(
 
     var chosen = instructions[0];
     var any_are_null = false;
+    var make_the_slice_const = false;
+    var convert_to_slice = false;
     var chosen_i: usize = 0;
     for (instructions[1..]) |candidate, candidate_i| {
         const candidate_ty = sema.typeOf(candidate);
@@ -16955,6 +16957,46 @@ fn resolvePeerTypes(
                         continue;
                     }
                 }
+
+                // *[N]T and *[M]T
+                // verify both are pointers to known lengths
+                if (chosen_ty_tag == .Pointer and
+                    chosen_ty.ptrSize() == .One and
+                    candidate_ty.ptrSize() == .One)
+                {
+                    // verify both pointers are two arrays
+                    const chosen_child_ty = chosen_ty.childType();
+                    const candidate_child_ty = candidate_ty.childType();
+                    if (chosen_child_ty.zigTypeTag() == .Array and candidate_child_ty.zigTypeTag() == .Array) {
+                        // If there is a sentinel, it must match
+                        if (chosen_child_ty.sentinel()) |chosen_sentinel| {
+                            if (candidate_child_ty.sentinel()) |candidate_sentinel| {
+                                if (!chosen_sentinel.eql(candidate_sentinel, chosen_child_ty)) {
+                                    continue;
+                                }
+                            } else {
+                                continue;
+                            }
+                        }
+
+                        // If we can cerce the element types, then we can do this.
+                        const chosen_elem_ty = chosen_child_ty.elemType2();
+                        const candidate_elem_ty = candidate_child_ty.elemType2();
+                        if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
+                            chosen = candidate;
+                            chosen_i = candidate_i + 1;
+
+                            convert_to_slice = true;
+
+                            // If one of the pointers is to const data, the slice
+                            // must also be const.
+                            if (candidate_child_ty.isConstPtr() or chosen_child_ty.isConstPtr())
+                                make_the_slice_const = true;
+
+                            continue;
+                        }
+                    }
+                }
             },
             .Optional => {
                 var opt_child_buf: Type.Payload.ElemType = undefined;
@@ -17037,6 +17079,22 @@ fn resolvePeerTypes(
         }
     }
 
+    if (convert_to_slice) {
+        // turn *[N]T => []T
+        const chosen_child_ty = chosen_ty.childType();
+        var info = chosen_ty.ptrInfo();
+        info.data.sentinel = chosen_child_ty.sentinel();
+        info.data.size = .Slice;
+        info.data.mutable = chosen_child_ty.isConstPtr() or make_the_slice_const;
+        info.data.pointee_type = switch (chosen_child_ty.tag()) {
+            .array => chosen_child_ty.elemType2(),
+            .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),
+            else => unreachable,
+        };
+
+        return Type.ptr(sema.arena, info.data);
+    }
+
     return chosen_ty;
 }
 
test/behavior/cast.zig
@@ -777,8 +777,6 @@ test "peer type resolve string lit with sentinel-terminated mutable slice" {
 }
 
 test "peer type resolve array pointers, one of them const" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     var array1: [4]u8 = undefined;
     const array2: [5]u8 = undefined;
     comptime try expect(@TypeOf(&array1, &array2) == []const u8);