authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-26 18:49:44-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-26 18:49:44-05:00
loge81b21a0ea955422835fb42a14bfa2db6bd74146
tree658b8a3c08eefb15b210e040ccc28345e5f39a32
parentbf3c88b68d9f8042b79b7d69d401429811d9de7c
parent156316bc7c3797362b5d16da320884a7aadabd6f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10992 from mitchellh/peer-slices

stage2: peer resolve *[N]T to []T and E![]T and [*]T, handle in-memory coercion

2 files changed, 227 insertions(+), 49 deletions(-)

src/Sema.zig+117
...@@ -17100,6 +17100,18 @@ fn resolvePeerTypes(...@@ -17100,6 +17100,18 @@ fn resolvePeerTypes(
17100 const chosen_ty = sema.typeOf(chosen);17100 const chosen_ty = sema.typeOf(chosen);
17101 if (candidate_ty.eql(chosen_ty))17101 if (candidate_ty.eql(chosen_ty))
17102 continue;17102 continue;
17103
17104 // If the candidate can coerce into our chosen type, we're done.
17105 // If the chosen type can coerce into the candidate, use that.
17106 if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
17107 continue;
17108 }
17109 if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
17110 chosen = candidate;
17111 chosen_i = candidate_i + 1;
17112 continue;
17113 }
17114
17103 const candidate_ty_tag = candidate_ty.zigTypeTag();17115 const candidate_ty_tag = candidate_ty.zigTypeTag();
17104 const chosen_ty_tag = chosen_ty.zigTypeTag();17116 const chosen_ty_tag = chosen_ty.zigTypeTag();
1710517117
...@@ -17180,6 +17192,30 @@ fn resolvePeerTypes(...@@ -17180,6 +17192,30 @@ fn resolvePeerTypes(
17180 },17192 },
17181 else => {},17193 else => {},
17182 },17194 },
17195 .ErrorUnion => {
17196 const payload_ty = candidate_ty.errorUnionPayload();
17197 if (chosen_ty_tag == .Pointer and
17198 chosen_ty.ptrSize() == .One and
17199 chosen_ty.childType().zigTypeTag() == .Array and
17200 payload_ty.isSlice())
17201 {
17202 const chosen_child_ty = chosen_ty.childType();
17203 const chosen_elem_ty = chosen_child_ty.elemType2();
17204 const candidate_elem_ty = payload_ty.elemType2();
17205 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
17206 chosen = candidate;
17207 chosen_i = candidate_i + 1;
17208
17209 convert_to_slice = false; // it already is a slice
17210
17211 // If the prev pointer is const then we need to const
17212 if (chosen_child_ty.isConstPtr())
17213 make_the_slice_const = true;
17214
17215 continue;
17216 }
17217 }
17218 },
17183 .Pointer => {17219 .Pointer => {
17184 if (candidate_ty.ptrSize() == .C) {17220 if (candidate_ty.ptrSize() == .C) {
17185 if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) {17221 if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) {
...@@ -17192,6 +17228,80 @@ fn resolvePeerTypes(...@@ -17192,6 +17228,80 @@ fn resolvePeerTypes(
17192 }17228 }
17193 }17229 }
1719417230
17231 // *[N]T to [*]T
17232 if (candidate_ty.ptrSize() == .Many and
17233 chosen_ty_tag == .Pointer and
17234 chosen_ty.ptrSize() == .One and
17235 chosen_ty.childType().zigTypeTag() == .Array)
17236 {
17237 chosen = candidate;
17238 chosen_i = candidate_i + 1;
17239
17240 convert_to_slice = false;
17241
17242 if (chosen_ty.childType().isConstPtr() and !candidate_ty.childType().isConstPtr())
17243 make_the_slice_const = true;
17244
17245 continue;
17246 }
17247
17248 // *[N]T to [*]T (prev is many pointer)
17249 if (candidate_ty.ptrSize() == .One and
17250 candidate_ty.childType().zigTypeTag() == .Array and
17251 chosen_ty_tag == .Pointer and
17252 chosen_ty.ptrSize() == .Many)
17253 {
17254 if (candidate_ty.childType().isConstPtr() and !chosen_ty.childType().isConstPtr())
17255 make_the_slice_const = true;
17256
17257 continue;
17258 }
17259
17260 // *[N]T to []T (prev is slice)
17261 // *[N]T to E![]T
17262 if ((chosen_ty.isSlice() or (chosen_ty_tag == .ErrorUnion and chosen_ty.errorUnionPayload().isSlice())) and
17263 candidate_ty.ptrSize() == .One and
17264 candidate_ty.childType().zigTypeTag() == .Array)
17265 {
17266 const chosen_elem_ty = switch (chosen_ty_tag) {
17267 .ErrorUnion => chosen_ty.errorUnionPayload().elemType2(),
17268 else => chosen_ty.elemType2(),
17269 };
17270 const candidate_elem_ty = candidate_ty.childType().elemType2();
17271 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
17272 convert_to_slice = false; // it already is a slice
17273
17274 // If the pointer is const then we need to const
17275 if (candidate_ty.childType().isConstPtr())
17276 make_the_slice_const = true;
17277
17278 continue;
17279 }
17280 }
17281
17282 // *[N]T to []T (current is slice)
17283 if (chosen_ty_tag == .Pointer and
17284 chosen_ty.ptrSize() == .One and
17285 chosen_ty.childType().zigTypeTag() == .Array and
17286 candidate_ty.isSlice())
17287 {
17288 const chosen_child_ty = chosen_ty.childType();
17289 const chosen_elem_ty = chosen_child_ty.elemType2();
17290 const candidate_elem_ty = candidate_ty.elemType2();
17291 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
17292 chosen = candidate;
17293 chosen_i = candidate_i + 1;
17294
17295 convert_to_slice = false; // it already is a slice
17296
17297 // If the prev pointer is const then we need to const
17298 if (chosen_child_ty.isConstPtr())
17299 make_the_slice_const = true;
17300
17301 continue;
17302 }
17303 }
17304
17195 // *[N]T and *[M]T17305 // *[N]T and *[M]T
17196 // verify both are pointers to known lengths17306 // verify both are pointers to known lengths
17197 if (chosen_ty_tag == .Pointer and17307 if (chosen_ty_tag == .Pointer and
...@@ -17329,6 +17439,13 @@ fn resolvePeerTypes(...@@ -17329,6 +17439,13 @@ fn resolvePeerTypes(
17329 return Type.ptr(sema.arena, info.data);17439 return Type.ptr(sema.arena, info.data);
17330 }17440 }
1733117441
17442 if (make_the_slice_const) {
17443 // turn []T => []const T
17444 var info = chosen_ty.ptrInfo();
17445 info.data.mutable = false;
17446 return Type.ptr(sema.arena, info.data);
17447 }
17448
17332 return chosen_ty;17449 return chosen_ty;
17333}17450}
1733417451
test/behavior/cast.zig+110-49
...@@ -358,7 +358,10 @@ fn testCastIntToErr(err: anyerror) !void {...@@ -358,7 +358,10 @@ fn testCastIntToErr(err: anyerror) !void {
358}358}
359359
360test "peer resolve array and const slice" {360test "peer resolve array and const slice" {
361 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
362365
363 try testPeerResolveArrayConstSlice(true);366 try testPeerResolveArrayConstSlice(true);
364 comptime try testPeerResolveArrayConstSlice(true);367 comptime try testPeerResolveArrayConstSlice(true);
...@@ -415,7 +418,10 @@ fn gimmeErrOrSlice() anyerror![]u8 {...@@ -415,7 +418,10 @@ fn gimmeErrOrSlice() anyerror![]u8 {
415}418}
416419
417test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {420test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
418 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
422 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
424 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
419425
420 const S = struct {426 const S = struct {
421 fn doTheTest() anyerror!void {427 fn doTheTest() anyerror!void {
...@@ -494,7 +500,10 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {...@@ -494,7 +500,10 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
494}500}
495501
496test "single-item pointer of array to slice to unknown length pointer" {502test "single-item pointer of array to slice to unknown length pointer" {
497 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
498507
499 try testCastPtrOfArrayToSliceAndPtr();508 try testCastPtrOfArrayToSliceAndPtr();
500 comptime try testCastPtrOfArrayToSliceAndPtr();509 comptime try testCastPtrOfArrayToSliceAndPtr();
...@@ -609,17 +618,25 @@ test "peer type resolution: unreachable, error set, unreachable" {...@@ -609,17 +618,25 @@ test "peer type resolution: unreachable, error set, unreachable" {
609}618}
610619
611test "peer cast *[0]T to E![]const T" {620test "peer cast *[0]T to E![]const T" {
612 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO621 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
622 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
624 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
613625
614 var buffer: [5]u8 = "abcde".*;626 var buffer: [5]u8 = "abcde".*;
615 var buf: anyerror![]const u8 = buffer[0..];627 var buf: anyerror![]const u8 = buffer[0..];
616 var b = false;628 var b = false;
617 var y = if (b) &[0]u8{} else buf;629 var y = if (b) &[0]u8{} else buf;
630 var z = if (!b) buf else &[0]u8{};
618 try expect(mem.eql(u8, "abcde", y catch unreachable));631 try expect(mem.eql(u8, "abcde", y catch unreachable));
632 try expect(mem.eql(u8, "abcde", z catch unreachable));
619}633}
620634
621test "peer cast *[0]T to []const T" {635test "peer cast *[0]T to []const T" {
622 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
637 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
638 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
639 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
623640
624 var buffer: [5]u8 = "abcde".*;641 var buffer: [5]u8 = "abcde".*;
625 var buf: []const u8 = buffer[0..];642 var buf: []const u8 = buffer[0..];
...@@ -628,6 +645,18 @@ test "peer cast *[0]T to []const T" {...@@ -628,6 +645,18 @@ test "peer cast *[0]T to []const T" {
628 try expect(mem.eql(u8, "abcde", y));645 try expect(mem.eql(u8, "abcde", y));
629}646}
630647
648test "peer cast *[N]T to [*]T" {
649 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
650 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
653
654 var array = [4:99]i32{ 1, 2, 3, 4 };
655 var dest: [*]i32 = undefined;
656 try expect(@TypeOf(&array, dest) == [*]i32);
657 try expect(@TypeOf(dest, &array) == [*]i32);
658}
659
631test "peer resolution of string literals" {660test "peer resolution of string literals" {
632 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO661 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
633662
...@@ -648,55 +677,89 @@ test "peer resolution of string literals" {...@@ -648,55 +677,89 @@ test "peer resolution of string literals" {
648 comptime try S.doTheTest(.b);677 comptime try S.doTheTest(.b);
649}678}
650679
651test "type coercion related to sentinel-termination" {680test "peer cast [:x]T to []T" {
652 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO681 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
682 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
684 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
653685
654 const S = struct {686 const S = struct {
655 fn doTheTest() !void {687 fn doTheTest() !void {
656 // [:x]T to []T688 var array = [4:0]i32{ 1, 2, 3, 4 };
657 {689 var slice: [:0]i32 = &array;
658 var array = [4:0]i32{ 1, 2, 3, 4 };690 var dest: []i32 = slice;
659 var slice: [:0]i32 = &array;691 try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 }));
660 var dest: []i32 = slice;692 }
661 try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 }));693 };
662 }694 try S.doTheTest();
695 comptime try S.doTheTest();
696}
663697
664 // [*:x]T to [*]T698test "peer cast [N:x]T to [N]T" {
665 {699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
666 var array = [4:99]i32{ 1, 2, 3, 4 };700 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
667 var dest: [*]i32 = &array;701 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
668 try expect(dest[0] == 1);702 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
669 try expect(dest[1] == 2);
670 try expect(dest[2] == 3);
671 try expect(dest[3] == 4);
672 try expect(dest[4] == 99);
673 }
674703
675 // [N:x]T to [N]T704 const S = struct {
676 {705 fn doTheTest() !void {
677 var array = [4:0]i32{ 1, 2, 3, 4 };706 var array = [4:0]i32{ 1, 2, 3, 4 };
678 var dest: [4]i32 = array;707 var dest: [4]i32 = array;
679 try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 }));708 try expect(mem.eql(i32, &dest, &[_]i32{ 1, 2, 3, 4 }));
680 }709 }
710 };
711 try S.doTheTest();
712 comptime try S.doTheTest();
713}
681714
682 // *[N:x]T to *[N]T715test "peer cast *[N:x]T to *[N]T" {
683 {716 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684 var array = [4:0]i32{ 1, 2, 3, 4 };717 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
685 var dest: *[4]i32 = &array;718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
686 try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 }));719 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
687 }
688720
689 // [:x]T to [*:x]T721 const S = struct {
690 {722 fn doTheTest() !void {
691 var array = [4:0]i32{ 1, 2, 3, 4 };723 var array = [4:0]i32{ 1, 2, 3, 4 };
692 var slice: [:0]i32 = &array;724 var dest: *[4]i32 = &array;
693 var dest: [*:0]i32 = slice;725 try expect(mem.eql(i32, dest, &[_]i32{ 1, 2, 3, 4 }));
694 try expect(dest[0] == 1);726 }
695 try expect(dest[1] == 2);727 };
696 try expect(dest[2] == 3);728 try S.doTheTest();
697 try expect(dest[3] == 4);729 comptime try S.doTheTest();
698 try expect(dest[4] == 0);730}
699 }731
732test "peer cast [*:x]T to [*]T" {
733 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
734
735 const S = struct {
736 fn doTheTest() !void {
737 var array = [4:99]i32{ 1, 2, 3, 4 };
738 var dest: [*]i32 = &array;
739 try expect(dest[0] == 1);
740 try expect(dest[1] == 2);
741 try expect(dest[2] == 3);
742 try expect(dest[3] == 4);
743 try expect(dest[4] == 99);
744 }
745 };
746 try S.doTheTest();
747 comptime try S.doTheTest();
748}
749
750test "peer cast [:x]T to [*:x]T" {
751 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
752
753 const S = struct {
754 fn doTheTest() !void {
755 var array = [4:0]i32{ 1, 2, 3, 4 };
756 var slice: [:0]i32 = &array;
757 var dest: [*:0]i32 = slice;
758 try expect(dest[0] == 1);
759 try expect(dest[1] == 2);
760 try expect(dest[2] == 3);
761 try expect(dest[3] == 4);
762 try expect(dest[4] == 0);
700 }763 }
701 };764 };
702 try S.doTheTest();765 try S.doTheTest();
...@@ -746,8 +809,6 @@ test "peer type resolution implicit cast to variable type" {...@@ -746,8 +809,6 @@ test "peer type resolution implicit cast to variable type" {
746}809}
747810
748test "variable initialization uses result locations properly with regards to the type" {811test "variable initialization uses result locations properly with regards to the type" {
749 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
750
751 var b = true;812 var b = true;
752 const x: i32 = if (b) 1 else 2;813 const x: i32 = if (b) 1 else 2;
753 try expect(x == 1);814 try expect(x == 1);