From 117ef22d3cb86858632d84699e19a90c24745d89 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 13:21:07 -0800 Subject: [PATCH 01/10] stage2: peer resolve *[N]T to []T (and vice versa) --- src/Sema.zig | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index ef9ba41bec..62523a6a01 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -17085,6 +17085,47 @@ fn resolvePeerTypes( } } + // *[N]T to []T (prev is slice) + if (chosen_ty.isSlice() and + candidate_ty.ptrSize() == .One and + candidate_ty.childType().zigTypeTag() == .Array) + { + const chosen_elem_ty = chosen_ty.elemType2(); + const candidate_elem_ty = candidate_ty.childType().elemType2(); + if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) { + convert_to_slice = false; // it already is a slice + + // If the pointer is const then we need to const + if (candidate_ty.childType().isConstPtr()) + make_the_slice_const = true; + + continue; + } + } + + // *[N]T to []T (current is slice) + if (chosen_ty_tag == .Pointer and + chosen_ty.ptrSize() == .One and + chosen_ty.childType().zigTypeTag() == .Array and + candidate_ty.isSlice()) + { + const chosen_child_ty = chosen_ty.childType(); + const chosen_elem_ty = chosen_child_ty.elemType2(); + const candidate_elem_ty = candidate_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 = false; // it already is a slice + + // If the prev pointer is const then we need to const + if (chosen_child_ty.isConstPtr()) + make_the_slice_const = true; + + continue; + } + } + // *[N]T and *[M]T // verify both are pointers to known lengths if (chosen_ty_tag == .Pointer and @@ -17222,6 +17263,15 @@ fn resolvePeerTypes( return Type.ptr(sema.arena, info.data); } + if (make_the_slice_const) { + // turn []T => []const T + var info = chosen_ty.ptrInfo(); + info.data.mutable = false; + + std.debug.print("TYPE: {}\n", .{Type.ptr(sema.arena, info.data)}); + return Type.ptr(sema.arena, info.data); + } + return chosen_ty; } From 101918198260482d98f6690f0ce3b1fb77a30595 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 13:33:11 -0800 Subject: [PATCH 02/10] stage2: *[N]T and E![]T --- src/Sema.zig | 32 ++++++++++++++++++++++++++++++-- test/behavior/cast.zig | 12 ++---------- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 62523a6a01..a03db84d2c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -17073,6 +17073,30 @@ fn resolvePeerTypes( }, else => {}, }, + .ErrorUnion => { + const payload_ty = candidate_ty.errorUnionPayload(); + if (chosen_ty_tag == .Pointer and + chosen_ty.ptrSize() == .One and + chosen_ty.childType().zigTypeTag() == .Array and + payload_ty.isSlice()) + { + const chosen_child_ty = chosen_ty.childType(); + const chosen_elem_ty = chosen_child_ty.elemType2(); + const candidate_elem_ty = payload_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 = false; // it already is a slice + + // If the prev pointer is const then we need to const + if (chosen_child_ty.isConstPtr()) + make_the_slice_const = true; + + continue; + } + } + }, .Pointer => { if (candidate_ty.ptrSize() == .C) { if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) { @@ -17086,11 +17110,15 @@ fn resolvePeerTypes( } // *[N]T to []T (prev is slice) - if (chosen_ty.isSlice() and + // *[N]T to E![]T + if ((chosen_ty.isSlice() or (chosen_ty_tag == .ErrorUnion and chosen_ty.errorUnionPayload().isSlice())) and candidate_ty.ptrSize() == .One and candidate_ty.childType().zigTypeTag() == .Array) { - const chosen_elem_ty = chosen_ty.elemType2(); + const chosen_elem_ty = switch (chosen_ty_tag) { + .ErrorUnion => chosen_ty.errorUnionPayload().elemType2(), + else => chosen_ty.elemType2(), + }; const candidate_elem_ty = candidate_ty.childType().elemType2(); if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) { convert_to_slice = false; // it already is a slice diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 0ddbf6458a..e37f1fb974 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -358,8 +358,6 @@ fn testCastIntToErr(err: anyerror) !void { } test "peer resolve array and const slice" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - try testPeerResolveArrayConstSlice(true); comptime try testPeerResolveArrayConstSlice(true); } @@ -492,8 +490,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { } test "single-item pointer of array to slice to unknown length pointer" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - try testCastPtrOfArrayToSliceAndPtr(); comptime try testCastPtrOfArrayToSliceAndPtr(); } @@ -607,18 +603,16 @@ test "peer type resolution: unreachable, error set, unreachable" { } test "peer cast *[0]T to E![]const T" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - var buffer: [5]u8 = "abcde".*; var buf: anyerror![]const u8 = buffer[0..]; var b = false; var y = if (b) &[0]u8{} else buf; + var z = if (!b) buf else &[0]u8{}; try expect(mem.eql(u8, "abcde", y catch unreachable)); + try expect(mem.eql(u8, "abcde", z catch unreachable)); } test "peer cast *[0]T to []const T" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - var buffer: [5]u8 = "abcde".*; var buf: []const u8 = buffer[0..]; var b = false; @@ -744,8 +738,6 @@ test "peer type resolution implicit cast to variable type" { } test "variable initialization uses result locations properly with regards to the type" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - var b = true; const x: i32 = if (b) 1 else 2; try expect(x == 1); From bcf3eb5663af744dc5b6da7ec729d153c366dd42 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 13:35:36 -0800 Subject: [PATCH 03/10] stage2: another passing test --- test/behavior/cast.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index e37f1fb974..1c6a8feb5e 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -411,8 +411,6 @@ fn gimmeErrOrSlice() anyerror![]u8 { } test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - const S = struct { fn doTheTest() anyerror!void { { From 4a6f91802929ce62ce0cedff5258fd9afb8a6dcb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 13:37:07 -0800 Subject: [PATCH 04/10] stage2: remove extranneous debug --- src/Sema.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index a03db84d2c..f30b8fd16c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -17295,8 +17295,6 @@ fn resolvePeerTypes( // turn []T => []const T var info = chosen_ty.ptrInfo(); info.data.mutable = false; - - std.debug.print("TYPE: {}\n", .{Type.ptr(sema.arena, info.data)}); return Type.ptr(sema.arena, info.data); } From e442f88b767a2b70a7e396501453013d0a364974 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 17:03:49 -0800 Subject: [PATCH 05/10] stage2: add other backend skips until they determine they pass --- test/behavior/cast.zig | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 1c6a8feb5e..141cba35df 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -358,6 +358,11 @@ fn testCastIntToErr(err: anyerror) !void { } test "peer resolve array and const slice" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + try testPeerResolveArrayConstSlice(true); comptime try testPeerResolveArrayConstSlice(true); } @@ -411,6 +416,11 @@ fn gimmeErrOrSlice() anyerror![]u8 { } test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + const S = struct { fn doTheTest() anyerror!void { { @@ -488,6 +498,11 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { } test "single-item pointer of array to slice to unknown length pointer" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + try testCastPtrOfArrayToSliceAndPtr(); comptime try testCastPtrOfArrayToSliceAndPtr(); } @@ -601,6 +616,11 @@ test "peer type resolution: unreachable, error set, unreachable" { } test "peer cast *[0]T to E![]const T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + var buffer: [5]u8 = "abcde".*; var buf: anyerror![]const u8 = buffer[0..]; var b = false; @@ -611,6 +631,11 @@ test "peer cast *[0]T to E![]const T" { } test "peer cast *[0]T to []const T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + var buffer: [5]u8 = "abcde".*; var buf: []const u8 = buffer[0..]; var b = false; From 943ee59bb1524a46dd13af6a55d30025e25dd061 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 17:17:47 -0800 Subject: [PATCH 06/10] stage2: *[N]T to [*]T (and vice versa) --- src/Sema.zig | 29 +++++++++++++++++++++++++++++ test/behavior/cast.zig | 12 ++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index f30b8fd16c..af240d43d1 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -17109,6 +17109,35 @@ fn resolvePeerTypes( } } + // *[N]T to [*]T + if (candidate_ty.ptrSize() == .Many and + chosen_ty_tag == .Pointer and + chosen_ty.ptrSize() == .One and + chosen_ty.childType().zigTypeTag() == .Array) + { + chosen = candidate; + chosen_i = candidate_i + 1; + + convert_to_slice = false; + + if (chosen_ty.childType().isConstPtr() and !candidate_ty.childType().isConstPtr()) + make_the_slice_const = true; + + continue; + } + + // *[N]T to [*]T (prev is many pointer) + if (candidate_ty.ptrSize() == .One and + candidate_ty.childType().zigTypeTag() == .Array and + chosen_ty_tag == .Pointer and + chosen_ty.ptrSize() == .Many) + { + if (candidate_ty.childType().isConstPtr() and !chosen_ty.childType().isConstPtr()) + make_the_slice_const = true; + + continue; + } + // *[N]T to []T (prev is slice) // *[N]T to E![]T if ((chosen_ty.isSlice() or (chosen_ty_tag == .ErrorUnion and chosen_ty.errorUnionPayload().isSlice())) and diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 141cba35df..3d5b5bd4fb 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -643,6 +643,18 @@ test "peer cast *[0]T to []const T" { try expect(mem.eql(u8, "abcde", y)); } +test "peer cast *[N]T to [*]T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + var array = [4:99]i32{ 1, 2, 3, 4 }; + var dest: [*]i32 = undefined; + try expect(@TypeOf(&array, dest) == [*]i32); + try expect(@TypeOf(dest, &array) == [*]i32); +} + test "peer resolution of string literals" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO From 91af552f87817f3a5fa23d812cecc79649c7e506 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 18:47:10 -0800 Subject: [PATCH 07/10] stage2: resolve peer types that trivially coerce --- src/Sema.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Sema.zig b/src/Sema.zig index af240d43d1..650349f744 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -16993,6 +16993,18 @@ fn resolvePeerTypes( const chosen_ty = sema.typeOf(chosen); if (candidate_ty.eql(chosen_ty)) continue; + + // If the candidate can coernce into our chosen type, we're done. + // If the chosen type can coerce into the candidate, use that. + if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) { + continue; + } + if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) { + chosen = candidate; + chosen_i = candidate_i + 1; + continue; + } + const candidate_ty_tag = candidate_ty.zigTypeTag(); const chosen_ty_tag = chosen_ty.zigTypeTag(); From f0232fc07d3c8695de351d3000bc7eb3e3f1da5c Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 25 Feb 2022 18:56:27 -0800 Subject: [PATCH 08/10] stage2: split up the big sentinel peer cast test to multiple This way we can fix them one at a time. --- test/behavior/cast.zig | 105 ++++++++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 43 deletions(-) diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 3d5b5bd4fb..eda49e7de5 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -675,55 +675,74 @@ test "peer resolution of string literals" { comptime try S.doTheTest(.b); } -test "type coercion related to sentinel-termination" { +test "peer cast [:x]T to []T" { + const S = struct { + fn doTheTest() !void { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var slice: [:0]i32 = &array; + var dest: []i32 = slice; + try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "peer cast [N:x]T to [N]T" { + const S = struct { + fn doTheTest() !void { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var dest: [4]i32 = array; + try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "peer cast *[N:x]T to *[N]T" { + const S = struct { + fn doTheTest() !void { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var dest: *[4]i32 = &array; + try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + +test "peer cast [*:x]T to [*]T" { if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { - // [:x]T to []T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var slice: [:0]i32 = &array; - var dest: []i32 = slice; - try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); - } + var array = [4:99]i32{ 1, 2, 3, 4 }; + var dest: [*]i32 = &array; + try expect(dest[0] == 1); + try expect(dest[1] == 2); + try expect(dest[2] == 3); + try expect(dest[3] == 4); + try expect(dest[4] == 99); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} - // [*:x]T to [*]T - { - var array = [4:99]i32{ 1, 2, 3, 4 }; - var dest: [*]i32 = &array; - try expect(dest[0] == 1); - try expect(dest[1] == 2); - try expect(dest[2] == 3); - try expect(dest[3] == 4); - try expect(dest[4] == 99); - } +test "peer cast [:x]T to [*:x]T" { + if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO - // [N:x]T to [N]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var dest: [4]i32 = array; - try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 })); - } - - // *[N:x]T to *[N]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var dest: *[4]i32 = &array; - try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 })); - } - - // [:x]T to [*:x]T - { - var array = [4:0]i32{ 1, 2, 3, 4 }; - var slice: [:0]i32 = &array; - var dest: [*:0]i32 = slice; - try expect(dest[0] == 1); - try expect(dest[1] == 2); - try expect(dest[2] == 3); - try expect(dest[3] == 4); - try expect(dest[4] == 0); - } + const S = struct { + fn doTheTest() !void { + var array = [4:0]i32{ 1, 2, 3, 4 }; + var slice: [:0]i32 = &array; + var dest: [*:0]i32 = slice; + try expect(dest[0] == 1); + try expect(dest[1] == 2); + try expect(dest[2] == 3); + try expect(dest[3] == 4); + try expect(dest[4] == 0); } }; try S.doTheTest(); From a5c9e8a49486b8bfb1cd12fbb0581d3213aaa53b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 26 Feb 2022 09:33:03 -0800 Subject: [PATCH 09/10] typo in comment --- src/Sema.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sema.zig b/src/Sema.zig index 650349f744..5c75339910 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -16994,7 +16994,7 @@ fn resolvePeerTypes( if (candidate_ty.eql(chosen_ty)) continue; - // If the candidate can coernce into our chosen type, we're done. + // If the candidate can coerce into our chosen type, we're done. // If the chosen type can coerce into the candidate, use that. if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) { continue; From 156316bc7c3797362b5d16da320884a7aadabd6f Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 26 Feb 2022 13:56:50 -0800 Subject: [PATCH 10/10] stage2: skip more tests for native backends --- test/behavior/cast.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index eda49e7de5..fb35310b76 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -676,6 +676,11 @@ test "peer resolution of string literals" { } test "peer cast [:x]T to []T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + const S = struct { fn doTheTest() !void { var array = [4:0]i32{ 1, 2, 3, 4 }; @@ -689,6 +694,11 @@ test "peer cast [:x]T to []T" { } test "peer cast [N:x]T to [N]T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + const S = struct { fn doTheTest() !void { var array = [4:0]i32{ 1, 2, 3, 4 }; @@ -701,6 +711,11 @@ test "peer cast [N:x]T to [N]T" { } test "peer cast *[N:x]T to *[N]T" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + const S = struct { fn doTheTest() !void { var array = [4:0]i32{ 1, 2, 3, 4 };