authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-04 01:16:47-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-04 01:16:47-05:00
log7605166426527c7d169ecad89d8de6799935f5ca
treefc00c36767b6c15a444ec5c57f69778517ac740b
parentc9ee3c1e474a7b10fb806b60ef108057395a3cca
parent63c5c510b1a083fbbca4145b1b53d39da9b0fd81
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11052 from mitchellh/peer-c

stage2: peer resolve *T and [*c]T

2 files changed, 139 insertions(+), 125 deletions(-)

src/Sema.zig+134-120
......@@ -18279,126 +18279,126 @@ fn resolvePeerTypes(
1827918279 },
1828018280 },
1828118281 .Pointer => {
18282 if (candidate_ty.ptrSize() == .C) {
18283 if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) {
18284 chosen = candidate;
18285 chosen_i = candidate_i + 1;
18286 continue;
18287 }
18288 if (chosen_ty_tag == .Pointer and chosen_ty.ptrSize() != .Slice) {
18289 continue;
18290 }
18291 }
18292
18293 // *[N]T to [*]T
18294 if (candidate_ty.ptrSize() == .Many and
18295 chosen_ty_tag == .Pointer and
18296 chosen_ty.ptrSize() == .One and
18297 chosen_ty.childType().zigTypeTag() == .Array)
18298 {
18299 chosen = candidate;
18300 chosen_i = candidate_i + 1;
18301
18302 convert_to_slice = false;
18303
18304 if (chosen_ty.isConstPtr() and !candidate_ty.isConstPtr())
18305 seen_const = true;
18306
18307 continue;
18308 }
18309
18310 // *[N]T to [*]T (prev is many pointer)
18311 if (candidate_ty.ptrSize() == .One and
18312 candidate_ty.childType().zigTypeTag() == .Array and
18313 chosen_ty_tag == .Pointer and
18314 chosen_ty.ptrSize() == .Many)
18315 {
18316 if (candidate_ty.isConstPtr() and !chosen_ty.isConstPtr())
18317 seen_const = true;
18282 const cand_info = candidate_ty.ptrInfo().data;
18283 switch (chosen_ty_tag) {
18284 .Pointer => {
18285 const chosen_info = chosen_ty.ptrInfo().data;
1831818286
18319 continue;
18320 }
18287 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
1832118288
18322 // *[N]T to []T (prev is slice)
18323 // *[N]T to E![]T
18324 if ((chosen_ty.isSlice() or (chosen_ty_tag == .ErrorUnion and chosen_ty.errorUnionPayload().isSlice())) and
18325 candidate_ty.ptrSize() == .One and
18326 candidate_ty.childType().zigTypeTag() == .Array)
18327 {
18328 const chosen_elem_ty = switch (chosen_ty_tag) {
18329 .ErrorUnion => chosen_ty.errorUnionPayload().elemType2(),
18330 else => chosen_ty.elemType2(),
18331 };
18332 const candidate_elem_ty = candidate_ty.childType().elemType2();
18333 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
18334 convert_to_slice = false; // it already is a slice
18335
18336 // If the pointer is const then we need to const
18337 if (candidate_ty.isConstPtr())
18338 seen_const = true;
18339
18340 continue;
18341 }
18342 }
18289 // *[N]T to [*]T
18290 // *[N]T to []T
18291 if ((cand_info.size == .Many or cand_info.size == .Slice) and
18292 chosen_info.size == .One and
18293 chosen_info.pointee_type.zigTypeTag() == .Array)
18294 {
18295 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
18296 convert_to_slice = false;
18297 chosen = candidate;
18298 chosen_i = candidate_i + 1;
18299 continue;
18300 }
18301 if (cand_info.size == .One and
18302 cand_info.pointee_type.zigTypeTag() == .Array and
18303 (chosen_info.size == .Many or chosen_info.size == .Slice))
18304 {
18305 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
18306 convert_to_slice = false;
18307 continue;
18308 }
1834318309
18344 // *[N]T to []T (current is slice)
18345 if (chosen_ty_tag == .Pointer and
18346 chosen_ty.ptrSize() == .One and
18347 chosen_ty.childType().zigTypeTag() == .Array and
18348 candidate_ty.isSlice())
18349 {
18350 const chosen_child_ty = chosen_ty.childType();
18351 const chosen_elem_ty = chosen_child_ty.elemType2();
18352 const candidate_elem_ty = candidate_ty.elemType2();
18353 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
18354 chosen = candidate;
18355 chosen_i = candidate_i + 1;
18310 // *[N]T and *[M]T
18311 // Verify both are single-pointers to arrays.
18312 // Keep the one whose element type can be coerced into.
18313 if (chosen_info.size == .One and
18314 cand_info.size == .One and
18315 chosen_info.pointee_type.zigTypeTag() == .Array and
18316 cand_info.pointee_type.zigTypeTag() == .Array)
18317 {
18318 const chosen_elem_ty = chosen_info.pointee_type.childType();
18319 const cand_elem_ty = cand_info.pointee_type.childType();
1835618320
18357 convert_to_slice = false; // it already is a slice
18321 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src);
18322 if (chosen_ok) {
18323 convert_to_slice = true;
18324 continue;
18325 }
1835818326
18359 // If the prev pointer is const then we need to const
18360 if (chosen_ty.isConstPtr())
18361 seen_const = true;
18327 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src);
18328 if (cand_ok) {
18329 convert_to_slice = true;
18330 chosen = candidate;
18331 chosen_i = candidate_i + 1;
18332 continue;
18333 }
1836218334
18363 continue;
18364 }
18365 }
18335 // They're both bad. Report error.
18336 // In the future we probably want to use the
18337 // coerceInMemoryAllowed error reporting mechanism,
18338 // however, for now we just fall through for the
18339 // "incompatible types" error below.
18340 }
1836618341
18367 // *[N]T and *[M]T
18368 // verify both are pointers to known lengths
18369 if (chosen_ty_tag == .Pointer and
18370 chosen_ty.ptrSize() == .One and
18371 candidate_ty.ptrSize() == .One)
18372 {
18373 // verify both pointers are two arrays
18374 const chosen_child_ty = chosen_ty.childType();
18375 const candidate_child_ty = candidate_ty.childType();
18376 if (chosen_child_ty.zigTypeTag() == .Array and candidate_child_ty.zigTypeTag() == .Array) {
18377 // If we can cerce the element types, then we can do this.
18378 const chosen_elem_ty = chosen_child_ty.elemType2();
18379 const candidate_elem_ty = candidate_child_ty.elemType2();
18380 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {
18381 // If there is a sentinel, it must match
18382 if (chosen_child_ty.sentinel()) |chosen_sentinel| {
18383 if (candidate_child_ty.sentinel()) |candidate_sentinel| {
18384 if (!chosen_sentinel.eql(candidate_sentinel, chosen_elem_ty))
18342 // [*c]T and any other pointer size
18343 // Whichever element type can coerce to the other one, is
18344 // the one we will keep. If they're both OK then we keep the
18345 // C pointer since it matches both single and many pointers.
18346 if (cand_info.size == .C or chosen_info.size == .C) {
18347 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src);
18348 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src);
18349
18350 if (cand_ok) {
18351 if (chosen_ok) {
18352 if (chosen_info.size == .C) {
18353 continue;
18354 } else {
18355 chosen = candidate;
18356 chosen_i = candidate_i + 1;
1838518357 continue;
18386 } else continue;
18358 }
18359 } else {
18360 chosen = candidate;
18361 chosen_i = candidate_i + 1;
18362 continue;
18363 }
18364 } else {
18365 if (chosen_ok) {
18366 continue;
18367 } else {
18368 // They're both bad. Report error.
18369 // In the future we probably want to use the
18370 // coerceInMemoryAllowed error reporting mechanism,
18371 // however, for now we just fall through for the
18372 // "incompatible types" error below.
18373 }
1838718374 }
18388
18375 }
18376 },
18377 .Int, .ComptimeInt => {
18378 if (cand_info.size == .C) {
1838918379 chosen = candidate;
1839018380 chosen_i = candidate_i + 1;
18391
18392 convert_to_slice = true;
18393
18394 // If one of the pointers is to const data, the slice
18395 // must also be const.
18396 if (candidate_child_ty.isConstPtr() or chosen_child_ty.isConstPtr())
18397 seen_const = true;
18398
1839918381 continue;
1840018382 }
18401 }
18383 },
18384 .ErrorUnion => {
18385 const chosen_ptr_ty = chosen_ty.errorUnionPayload();
18386 if (chosen_ptr_ty.zigTypeTag() == .Pointer) {
18387 const chosen_info = chosen_ptr_ty.ptrInfo().data;
18388
18389 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
18390
18391 // *[N]T to E![*]T
18392 // *[N]T to E![]T
18393 if (cand_info.size == .One and
18394 cand_info.pointee_type.zigTypeTag() == .Array and
18395 (chosen_info.size == .Many or chosen_info.size == .Slice))
18396 {
18397 continue;
18398 }
18399 }
18400 },
18401 else => {},
1840218402 }
1840318403 },
1840418404 .Optional => {
......@@ -18492,20 +18492,13 @@ fn resolvePeerTypes(
1849218492
1849318493 const chosen_ty = sema.typeOf(chosen);
1849418494
18495 if (any_are_null) {
18496 switch (chosen_ty.zigTypeTag()) {
18497 .Null, .Optional => return chosen_ty,
18498 else => return Type.optional(sema.arena, chosen_ty),
18499 }
18500 }
18501
1850218495 if (convert_to_slice) {
1850318496 // turn *[N]T => []T
1850418497 const chosen_child_ty = chosen_ty.childType();
1850518498 var info = chosen_ty.ptrInfo();
1850618499 info.data.sentinel = chosen_child_ty.sentinel();
1850718500 info.data.size = .Slice;
18508 info.data.mutable = seen_const or chosen_child_ty.isConstPtr();
18501 info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr());
1850918502 info.data.pointee_type = switch (chosen_child_ty.tag()) {
1851018503 .array => chosen_child_ty.elemType2(),
1851118504 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),
......@@ -18513,8 +18506,12 @@ fn resolvePeerTypes(
1851318506 };
1851418507
1851518508 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18516 const set_ty = err_set_ty orelse return new_ptr_ty;
18517 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
18509 const opt_ptr_ty = if (any_are_null)
18510 try Type.optional(sema.arena, new_ptr_ty)
18511 else
18512 new_ptr_ty;
18513 const set_ty = err_set_ty orelse return opt_ptr_ty;
18514 return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty);
1851818515 }
1851918516
1852018517 if (seen_const) {
......@@ -18525,20 +18522,37 @@ fn resolvePeerTypes(
1852518522 var info = ptr_ty.ptrInfo();
1852618523 info.data.mutable = false;
1852718524 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18525 const opt_ptr_ty = if (any_are_null)
18526 try Type.optional(sema.arena, new_ptr_ty)
18527 else
18528 new_ptr_ty;
1852818529 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
18529 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
18530 return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty);
1853018531 },
1853118532 .Pointer => {
1853218533 var info = chosen_ty.ptrInfo();
1853318534 info.data.mutable = false;
1853418535 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18535 const set_ty = err_set_ty orelse return new_ptr_ty;
18536 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);
18536 const opt_ptr_ty = if (any_are_null)
18537 try Type.optional(sema.arena, new_ptr_ty)
18538 else
18539 new_ptr_ty;
18540 const set_ty = err_set_ty orelse return opt_ptr_ty;
18541 return try Module.errorUnionType(sema.arena, set_ty, opt_ptr_ty);
1853718542 },
1853818543 else => return chosen_ty,
1853918544 }
1854018545 }
1854118546
18547 if (any_are_null) {
18548 const opt_ty = switch (chosen_ty.zigTypeTag()) {
18549 .Null, .Optional => chosen_ty,
18550 else => try Type.optional(sema.arena, chosen_ty),
18551 };
18552 const set_ty = err_set_ty orelse return opt_ty;
18553 return try Module.errorUnionType(sema.arena, set_ty, opt_ty);
18554 }
18555
1854218556 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {
1854318557 .ErrorSet => return ty,
1854418558 .ErrorUnion => {
test/behavior/pointers.zig+5-5
......@@ -128,8 +128,6 @@ fn testDerefPtrOneVal() !void {
128128}
129129
130130test "peer type resolution with C pointers" {
131 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
132
133131 var ptr_one: *u8 = undefined;
134132 var ptr_many: [*]u8 = undefined;
135133 var ptr_c: [*c]u8 = undefined;
......@@ -159,7 +157,11 @@ test "implicit casting between C pointer and optional non-C pointer" {
159157}
160158
161159test "implicit cast error unions with non-optional to optional pointer" {
162 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
163165
164166 const S = struct {
165167 fn doTheTest() !void {
......@@ -376,8 +378,6 @@ test "pointer arithmetic affects the alignment" {
376378}
377379
378380test "@ptrToInt on null optional at comptime" {
379 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
380
381381 {
382382 const pointer = @intToPtr(?*u8, 0x000);
383383 const x = @ptrToInt(pointer);