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(...@@ -18279,126 +18279,126 @@ fn resolvePeerTypes(
18279 },18279 },
18280 },18280 },
18281 .Pointer => {18281 .Pointer => {
18282 if (candidate_ty.ptrSize() == .C) {18282 const cand_info = candidate_ty.ptrInfo().data;
18283 if (chosen_ty_tag == .Int or chosen_ty_tag == .ComptimeInt) {18283 switch (chosen_ty_tag) {
18284 chosen = candidate;18284 .Pointer => {
18285 chosen_i = candidate_i + 1;18285 const chosen_info = chosen_ty.ptrInfo().data;
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;
1831818286
18319 continue;18287 seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
18320 }
1832118288
18322 // *[N]T to []T (prev is slice)18289 // *[N]T to [*]T
18323 // *[N]T to E![]T18290 // *[N]T to []T
18324 if ((chosen_ty.isSlice() or (chosen_ty_tag == .ErrorUnion and chosen_ty.errorUnionPayload().isSlice())) and18291 if ((cand_info.size == .Many or cand_info.size == .Slice) and
18325 candidate_ty.ptrSize() == .One and18292 chosen_info.size == .One and
18326 candidate_ty.childType().zigTypeTag() == .Array)18293 chosen_info.pointee_type.zigTypeTag() == .Array)
18327 {18294 {
18328 const chosen_elem_ty = switch (chosen_ty_tag) {18295 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
18329 .ErrorUnion => chosen_ty.errorUnionPayload().elemType2(),18296 convert_to_slice = false;
18330 else => chosen_ty.elemType2(),18297 chosen = candidate;
18331 };18298 chosen_i = candidate_i + 1;
18332 const candidate_elem_ty = candidate_ty.childType().elemType2();18299 continue;
18333 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {18300 }
18334 convert_to_slice = false; // it already is a slice18301 if (cand_info.size == .One and
1833518302 cand_info.pointee_type.zigTypeTag() == .Array and
18336 // If the pointer is const then we need to const18303 (chosen_info.size == .Many or chosen_info.size == .Slice))
18337 if (candidate_ty.isConstPtr())18304 {
18338 seen_const = true;18305 // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
1833918306 convert_to_slice = false;
18340 continue;18307 continue;
18341 }18308 }
18342 }
1834318309
18344 // *[N]T to []T (current is slice)18310 // *[N]T and *[M]T
18345 if (chosen_ty_tag == .Pointer and18311 // Verify both are single-pointers to arrays.
18346 chosen_ty.ptrSize() == .One and18312 // Keep the one whose element type can be coerced into.
18347 chosen_ty.childType().zigTypeTag() == .Array and18313 if (chosen_info.size == .One and
18348 candidate_ty.isSlice())18314 cand_info.size == .One and
18349 {18315 chosen_info.pointee_type.zigTypeTag() == .Array and
18350 const chosen_child_ty = chosen_ty.childType();18316 cand_info.pointee_type.zigTypeTag() == .Array)
18351 const chosen_elem_ty = chosen_child_ty.elemType2();18317 {
18352 const candidate_elem_ty = candidate_ty.elemType2();18318 const chosen_elem_ty = chosen_info.pointee_type.childType();
18353 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {18319 const cand_elem_ty = cand_info.pointee_type.childType();
18354 chosen = candidate;
18355 chosen_i = candidate_i + 1;
1835618320
18357 convert_to_slice = false; // it already is a slice18321 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 const18327 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src);
18360 if (chosen_ty.isConstPtr())18328 if (cand_ok) {
18361 seen_const = true;18329 convert_to_slice = true;
18330 chosen = candidate;
18331 chosen_i = candidate_i + 1;
18332 continue;
18333 }
1836218334
18363 continue;18335 // They're both bad. Report error.
18364 }18336 // In the future we probably want to use the
18365 }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]T18342 // [*c]T and any other pointer size
18368 // verify both are pointers to known lengths18343 // Whichever element type can coerce to the other one, is
18369 if (chosen_ty_tag == .Pointer and18344 // the one we will keep. If they're both OK then we keep the
18370 chosen_ty.ptrSize() == .One and18345 // C pointer since it matches both single and many pointers.
18371 candidate_ty.ptrSize() == .One)18346 if (cand_info.size == .C or chosen_info.size == .C) {
18372 {18347 const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src);
18373 // verify both pointers are two arrays18348 const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src);
18374 const chosen_child_ty = chosen_ty.childType();18349
18375 const candidate_child_ty = candidate_ty.childType();18350 if (cand_ok) {
18376 if (chosen_child_ty.zigTypeTag() == .Array and candidate_child_ty.zigTypeTag() == .Array) {18351 if (chosen_ok) {
18377 // If we can cerce the element types, then we can do this.18352 if (chosen_info.size == .C) {
18378 const chosen_elem_ty = chosen_child_ty.elemType2();18353 continue;
18379 const candidate_elem_ty = candidate_child_ty.elemType2();18354 } else {
18380 if ((try sema.coerceInMemoryAllowed(block, candidate_elem_ty, chosen_elem_ty, false, target, src, src)) == .ok) {18355 chosen = candidate;
18381 // If there is a sentinel, it must match18356 chosen_i = candidate_i + 1;
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))
18385 continue;18357 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 }
18387 }18374 }
1838818375 }
18376 },
18377 .Int, .ComptimeInt => {
18378 if (cand_info.size == .C) {
18389 chosen = candidate;18379 chosen = candidate;
18390 chosen_i = candidate_i + 1;18380 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
18399 continue;18381 continue;
18400 }18382 }
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 => {},
18402 }18402 }
18403 },18403 },
18404 .Optional => {18404 .Optional => {
...@@ -18492,20 +18492,13 @@ fn resolvePeerTypes(...@@ -18492,20 +18492,13 @@ fn resolvePeerTypes(
1849218492
18493 const chosen_ty = sema.typeOf(chosen);18493 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
18502 if (convert_to_slice) {18495 if (convert_to_slice) {
18503 // turn *[N]T => []T18496 // turn *[N]T => []T
18504 const chosen_child_ty = chosen_ty.childType();18497 const chosen_child_ty = chosen_ty.childType();
18505 var info = chosen_ty.ptrInfo();18498 var info = chosen_ty.ptrInfo();
18506 info.data.sentinel = chosen_child_ty.sentinel();18499 info.data.sentinel = chosen_child_ty.sentinel();
18507 info.data.size = .Slice;18500 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());
18509 info.data.pointee_type = switch (chosen_child_ty.tag()) {18502 info.data.pointee_type = switch (chosen_child_ty.tag()) {
18510 .array => chosen_child_ty.elemType2(),18503 .array => chosen_child_ty.elemType2(),
18511 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),18504 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),
...@@ -18513,8 +18506,12 @@ fn resolvePeerTypes(...@@ -18513,8 +18506,12 @@ fn resolvePeerTypes(
18513 };18506 };
1851418507
18515 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);18508 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);
18516 const set_ty = err_set_ty orelse return new_ptr_ty;18509 const opt_ptr_ty = if (any_are_null)
18517 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);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);
18518 }18515 }
1851918516
18520 if (seen_const) {18517 if (seen_const) {
...@@ -18525,20 +18522,37 @@ fn resolvePeerTypes(...@@ -18525,20 +18522,37 @@ fn resolvePeerTypes(
18525 var info = ptr_ty.ptrInfo();18522 var info = ptr_ty.ptrInfo();
18526 info.data.mutable = false;18523 info.data.mutable = false;
18527 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);18524 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;
18528 const set_ty = err_set_ty orelse chosen_ty.errorUnionSet();18529 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);
18530 },18531 },
18531 .Pointer => {18532 .Pointer => {
18532 var info = chosen_ty.ptrInfo();18533 var info = chosen_ty.ptrInfo();
18533 info.data.mutable = false;18534 info.data.mutable = false;
18534 const new_ptr_ty = try Type.ptr(sema.arena, target, info.data);18535 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 const opt_ptr_ty = if (any_are_null)
18536 return try Module.errorUnionType(sema.arena, set_ty, new_ptr_ty);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);
18537 },18542 },
18538 else => return chosen_ty,18543 else => return chosen_ty,
18539 }18544 }
18540 }18545 }
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
18542 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {18556 if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {
18543 .ErrorSet => return ty,18557 .ErrorSet => return ty,
18544 .ErrorUnion => {18558 .ErrorUnion => {
test/behavior/pointers.zig+5-5
...@@ -128,8 +128,6 @@ fn testDerefPtrOneVal() !void {...@@ -128,8 +128,6 @@ fn testDerefPtrOneVal() !void {
128}128}
129129
130test "peer type resolution with C pointers" {130test "peer type resolution with C pointers" {
131 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
132
133 var ptr_one: *u8 = undefined;131 var ptr_one: *u8 = undefined;
134 var ptr_many: [*]u8 = undefined;132 var ptr_many: [*]u8 = undefined;
135 var ptr_c: [*c]u8 = undefined;133 var ptr_c: [*c]u8 = undefined;
...@@ -159,7 +157,11 @@ test "implicit casting between C pointer and optional non-C pointer" {...@@ -159,7 +157,11 @@ test "implicit casting between C pointer and optional non-C pointer" {
159}157}
160158
161test "implicit cast error unions with non-optional to optional pointer" {159test "implicit cast error unions with non-optional to optional pointer" {
162 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO160 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
164 const S = struct {166 const S = struct {
165 fn doTheTest() !void {167 fn doTheTest() !void {
...@@ -376,8 +378,6 @@ test "pointer arithmetic affects the alignment" {...@@ -376,8 +378,6 @@ test "pointer arithmetic affects the alignment" {
376}378}
377379
378test "@ptrToInt on null optional at comptime" {380test "@ptrToInt on null optional at comptime" {
379 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
380
381 {381 {
382 const pointer = @intToPtr(?*u8, 0x000);382 const pointer = @intToPtr(?*u8, 0x000);
383 const x = @ptrToInt(pointer);383 const x = @ptrToInt(pointer);