authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-07 20:54:10+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-10 23:15:17+03:00
logb9f01bc39452042be1609b63f3066cfcac82f273
tree5db2748bb4a8f7fafc1d9c375d205b05fd391d1e
parentb9ed07227832a10e5a18667d6c7cbdffd2018da7

Sema: add detailed error notes to `coerceInMemoryAllowed`


34 files changed, 699 insertions(+), 226 deletions(-)

src/Sema.zig+526-73
...@@ -19931,7 +19931,7 @@ fn coerce(...@@ -19931,7 +19931,7 @@ fn coerce(
19931 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;19931 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
19932 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {19932 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
19933 .ok => {},19933 .ok => {},
19934 .no_match => break :single_item,19934 else => break :single_item,
19935 }19935 }
19936 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);19936 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
19937 }19937 }
...@@ -19951,7 +19951,7 @@ fn coerce(...@@ -19951,7 +19951,7 @@ fn coerce(
19951 const dst_elem_type = dest_info.pointee_type;19951 const dst_elem_type = dest_info.pointee_type;
19952 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {19952 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {
19953 .ok => {},19953 .ok => {},
19954 .no_match => break :src_array_ptr,19954 else => break :src_array_ptr,
19955 }19955 }
1995619956
19957 switch (dest_info.size) {19957 switch (dest_info.size) {
...@@ -19990,7 +19990,7 @@ fn coerce(...@@ -19990,7 +19990,7 @@ fn coerce(
19990 const dst_elem_type = dest_info.pointee_type;19990 const dst_elem_type = dest_info.pointee_type;
19991 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {19991 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
19992 .ok => {},19992 .ok => {},
19993 .no_match => break :src_c_ptr,19993 else => break :src_c_ptr,
19994 }19994 }
19995 // TODO add safety check for null pointer19995 // TODO add safety check for null pointer
19996 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);19996 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
...@@ -20034,7 +20034,7 @@ fn coerce(...@@ -20034,7 +20034,7 @@ fn coerce(
20034 inst_src,20034 inst_src,
20035 )) {20035 )) {
20036 .ok => {},20036 .ok => {},
20037 .no_match => break :p,20037 else => break :p,
20038 }20038 }
20039 if (inst_info.size == .Slice) {20039 if (inst_info.size == .Slice) {
20040 if (dest_info.sentinel == null or inst_info.sentinel == null or20040 if (dest_info.sentinel == null or inst_info.sentinel == null or
...@@ -20124,7 +20124,7 @@ fn coerce(...@@ -20124,7 +20124,7 @@ fn coerce(
20124 inst_src,20124 inst_src,
20125 )) {20125 )) {
20126 .ok => {},20126 .ok => {},
20127 .no_match => break :p,20127 else => break :p,
20128 }20128 }
2012920129
20130 if (dest_info.sentinel == null or inst_info.sentinel == null or20130 if (dest_info.sentinel == null or inst_info.sentinel == null or
...@@ -20356,14 +20356,348 @@ fn coerce(...@@ -20356,14 +20356,348 @@ fn coerce(
20356 return sema.addConstUndef(dest_ty);20356 return sema.addConstUndef(dest_ty);
20357 }20357 }
2035820358
20359 return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });20359 const msg = msg: {
20360 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
20361 errdefer msg.destroy(sema.gpa);
20362
20363 try in_memory_result.report(sema, block, inst_src, msg);
20364 break :msg msg;
20365 };
20366 return sema.failWithOwnedErrorMsg(block, msg);
20360}20367}
2036120368
20362const InMemoryCoercionResult = enum {20369const InMemoryCoercionResult = union(enum) {
20363 ok,20370 ok,
20364 no_match,20371 no_match: Pair,
20372 int_mismatch: Int,
20373 error_union_payload: PairAndChild,
20374 array_len: IntPair,
20375 array_sentinel: Sentinel,
20376 array_elem: PairAndChild,
20377 vector_len: IntPair,
20378 vector_elem: PairAndChild,
20379 optional_shape: Pair,
20380 optional_child: PairAndChild,
20381 from_anyerror,
20382 missing_error: []const []const u8,
20383 /// true if wanted is var args
20384 fn_var_args: bool,
20385 /// true if wanted is generic
20386 fn_generic: bool,
20387 fn_param_count: IntPair,
20388 fn_param_noalias: IntPair,
20389 fn_param_comptime: ComptimeParam,
20390 fn_param: Param,
20391 fn_cc: CC,
20392 fn_return_type: PairAndChild,
20393 ptr_child: PairAndChild,
20394 ptr_addrspace: AddressSpace,
20395 ptr_sentinel: Sentinel,
20396 ptr_size: Size,
20397 ptr_qualifiers: Qualifiers,
20398 ptr_allowzero: Pair,
20399 ptr_bit_range: BitRange,
20400 ptr_alignment: IntPair,
20401
20402 const Pair = struct {
20403 actual: Type,
20404 wanted: Type,
20405 };
20406
20407 const PairAndChild = struct {
20408 child: *InMemoryCoercionResult,
20409 actual: Type,
20410 wanted: Type,
20411 };
20412
20413 const Param = struct {
20414 child: *InMemoryCoercionResult,
20415 actual: Type,
20416 wanted: Type,
20417 index: u64,
20418 };
20419
20420 const ComptimeParam = struct {
20421 index: u64,
20422 wanted: bool,
20423 };
20424
20425 const Sentinel = struct {
20426 // unreachable_value indicates no sentinel
20427 actual: Value,
20428 wanted: Value,
20429 ty: Type,
20430 };
20431
20432 const Int = struct {
20433 actual_signedness: std.builtin.Signedness,
20434 wanted_signedness: std.builtin.Signedness,
20435 actual_bits: u16,
20436 wanted_bits: u16,
20437 };
20438
20439 const IntPair = struct {
20440 actual: u64,
20441 wanted: u64,
20442 };
20443
20444 const Size = struct {
20445 actual: std.builtin.Type.Pointer.Size,
20446 wanted: std.builtin.Type.Pointer.Size,
20447 };
20448
20449 const Qualifiers = struct {
20450 actual_const: bool,
20451 wanted_const: bool,
20452 actual_volatile: bool,
20453 wanted_volatile: bool,
20454 };
20455
20456 const AddressSpace = struct {
20457 actual: std.builtin.AddressSpace,
20458 wanted: std.builtin.AddressSpace,
20459 };
20460
20461 const CC = struct {
20462 actual: std.builtin.CallingConvention,
20463 wanted: std.builtin.CallingConvention,
20464 };
20465
20466 const BitRange = struct {
20467 actual_host: u16,
20468 wanted_host: u16,
20469 actual_offset: u16,
20470 wanted_offset: u16,
20471 };
20472
20473 fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult {
20474 const res = try arena.create(InMemoryCoercionResult);
20475 res.* = child.*;
20476 return res;
20477 }
20478
20479 fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void {
20480 var cur = res;
20481 while (true) switch (cur.*) {
20482 .ok => unreachable,
20483 .no_match => |types| {
20484 try sema.addDeclaredHereNote(msg, types.wanted);
20485 try sema.addDeclaredHereNote(msg, types.actual);
20486 break;
20487 },
20488 .int_mismatch => |int| {
20489 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{
20490 @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits,
20491 });
20492 break;
20493 },
20494 .error_union_payload => |pair| {
20495 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
20496 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20497 });
20498 cur = pair.child;
20499 },
20500 .array_len => |lens| {
20501 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{
20502 lens.actual, lens.wanted,
20503 });
20504 break;
20505 },
20506 .array_sentinel => |sentinel| {
20507 if (sentinel.actual.tag() != .unreachable_value) {
20508 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
20509 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20510 });
20511 } else {
20512 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
20513 sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20514 });
20515 }
20516 break;
20517 },
20518 .array_elem => |pair| {
20519 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
20520 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20521 });
20522 cur = pair.child;
20523 },
20524 .vector_len => |lens| {
20525 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{
20526 lens.actual, lens.wanted,
20527 });
20528 break;
20529 },
20530 .vector_elem => |pair| {
20531 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
20532 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20533 });
20534 cur = pair.child;
20535 },
20536 .optional_shape => |pair| {
20537 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{
20538 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20539 });
20540 break;
20541 },
20542 .optional_child => |pair| {
20543 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
20544 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20545 });
20546 cur = pair.child;
20547 },
20548 .from_anyerror => {
20549 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{});
20550 break;
20551 },
20552 .missing_error => |missing_errors| {
20553 for (missing_errors) |err| {
20554 try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err});
20555 }
20556 break;
20557 },
20558 .fn_var_args => |wanted_var_args| {
20559 if (wanted_var_args) {
20560 try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{});
20561 } else {
20562 try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{});
20563 }
20564 break;
20565 },
20566 .fn_generic => |wanted_generic| {
20567 if (wanted_generic) {
20568 try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{});
20569 } else {
20570 try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{});
20571 }
20572 break;
20573 },
20574 .fn_param_count => |lens| {
20575 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{
20576 lens.actual, lens.wanted,
20577 });
20578 break;
20579 },
20580 .fn_param_noalias => |param| {
20581 var index: u6 = 0;
20582 var actual_noalias = false;
20583 while (true) : (index += 1) {
20584 if (param.actual << index != param.wanted << index) {
20585 actual_noalias = (param.actual << index) == (1 << 31);
20586 }
20587 }
20588 if (!actual_noalias) {
20589 try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index});
20590 } else {
20591 try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index});
20592 }
20593 break;
20594 },
20595 .fn_param_comptime => |param| {
20596 if (param.wanted) {
20597 try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index});
20598 } else {
20599 try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index});
20600 }
20601 break;
20602 },
20603 .fn_param => |param| {
20604 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
20605 param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod),
20606 });
20607 cur = param.child;
20608 },
20609 .fn_cc => |cc| {
20610 try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) });
20611 break;
20612 },
20613 .fn_return_type => |pair| {
20614 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{
20615 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20616 });
20617 cur = pair.child;
20618 },
20619 .ptr_child => |pair| {
20620 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
20621 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20622 });
20623 cur = pair.child;
20624 },
20625 .ptr_addrspace => |@"addrspace"| {
20626 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) });
20627 break;
20628 },
20629 .ptr_sentinel => |sentinel| {
20630 if (sentinel.actual.tag() != .unreachable_value) {
20631 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
20632 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20633 });
20634 } else {
20635 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
20636 sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20637 });
20638 }
20639 break;
20640 },
20641 .ptr_size => |size| {
20642 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) });
20643 break;
20644 },
20645 .ptr_qualifiers => |qualifiers| {
20646 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const;
20647 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile;
20648 if (!ok_const) {
20649 try sema.errNote(block, src, msg, "cast discards const qualifier", .{});
20650 } else if (!ok_volatile) {
20651 try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{});
20652 }
20653 break;
20654 },
20655 .ptr_allowzero => |pair| {
20656 const wanted_allow_zero = pair.wanted.ptrAllowsZero();
20657 const actual_allow_zero = pair.actual.ptrAllowsZero();
20658 if (actual_allow_zero and !wanted_allow_zero) {
20659 try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{
20660 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20661 });
20662 } else {
20663 try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{
20664 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20665 });
20666 }
20667 break;
20668 },
20669 .ptr_bit_range => |bit_range| {
20670 if (bit_range.actual_host != bit_range.wanted_host) {
20671 try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{
20672 bit_range.actual_host, bit_range.wanted_host,
20673 });
20674 }
20675 if (bit_range.actual_offset != bit_range.wanted_offset) {
20676 try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{
20677 bit_range.actual_offset, bit_range.wanted_offset,
20678 });
20679 }
20680 break;
20681 },
20682 .ptr_alignment => |pair| {
20683 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
20684 pair.actual, pair.wanted,
20685 });
20686 break;
20687 },
20688 };
20689 }
20365};20690};
2036620691
20692fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
20693 return switch (size) {
20694 .One => "single",
20695 .Many => "many",
20696 .C => "C",
20697 .Slice => unreachable,
20698 };
20699}
20700
20367/// If pointers have the same representation in runtime memory, a bitcast AIR instruction20701/// If pointers have the same representation in runtime memory, a bitcast AIR instruction
20368/// may be used for the coercion.20702/// may be used for the coercion.
20369/// * `const` attribute can be gained20703/// * `const` attribute can be gained
...@@ -20373,8 +20707,6 @@ const InMemoryCoercionResult = enum {...@@ -20373,8 +20707,6 @@ const InMemoryCoercionResult = enum {
20373/// * bit offset attributes must match exactly20707/// * bit offset attributes must match exactly
20374/// * `*`/`[*]` must match exactly, but `[*c]` matches either one20708/// * `*`/`[*]` must match exactly, but `[*c]` matches either one
20375/// * sentinel-terminated pointers can coerce into `[*]`20709/// * sentinel-terminated pointers can coerce into `[*]`
20376/// TODO improve this function to report recursive compile errors like it does in stage1.
20377/// look at the function types_match_const_cast_only
20378fn coerceInMemoryAllowed(20710fn coerceInMemoryAllowed(
20379 sema: *Sema,20711 sema: *Sema,
20380 block: *Block,20712 block: *Block,
...@@ -20392,11 +20724,17 @@ fn coerceInMemoryAllowed(...@@ -20392,11 +20724,17 @@ fn coerceInMemoryAllowed(
20392 if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {20724 if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {
20393 const dest_info = dest_ty.intInfo(target);20725 const dest_info = dest_ty.intInfo(target);
20394 const src_info = src_ty.intInfo(target);20726 const src_info = src_ty.intInfo(target);
20395 if (dest_info.signedness == src_info.signedness and20727 if (dest_info.signedness != src_info.signedness or
20396 dest_info.bits == src_info.bits)20728 dest_info.bits != src_info.bits)
20397 {20729 {
20398 return .ok;20730 return InMemoryCoercionResult{ .int_mismatch = .{
20731 .actual_signedness = src_info.signedness,
20732 .wanted_signedness = dest_info.signedness,
20733 .actual_bits = src_info.bits,
20734 .wanted_bits = dest_info.bits,
20735 } };
20399 }20736 }
20737 return .ok;
20400 }20738 }
2040120739
20402 // Differently-named floats with the same number of bits.20740 // Differently-named floats with the same number of bits.
...@@ -20434,9 +20772,15 @@ fn coerceInMemoryAllowed(...@@ -20434,9 +20772,15 @@ fn coerceInMemoryAllowed(
2043420772
20435 // Error Unions20773 // Error Unions
20436 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {20774 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
20437 const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src);20775 const dest_payload = dest_ty.errorUnionPayload();
20438 if (child == .no_match) {20776 const src_payload = src_ty.errorUnionPayload();
20439 return child;20777 const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src);
20778 if (child != .ok) {
20779 return InMemoryCoercionResult{ .error_union_payload = .{
20780 .child = try child.dupe(sema.arena),
20781 .actual = src_payload,
20782 .wanted = dest_payload,
20783 } };
20440 }20784 }
20441 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);20785 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);
20442 }20786 }
...@@ -20447,57 +20791,89 @@ fn coerceInMemoryAllowed(...@@ -20447,57 +20791,89 @@ fn coerceInMemoryAllowed(
20447 }20791 }
2044820792
20449 // Arrays20793 // Arrays
20450 if (dest_tag == .Array and src_tag == .Array) arrays: {20794 if (dest_tag == .Array and src_tag == .Array) {
20451 const dest_info = dest_ty.arrayInfo();20795 const dest_info = dest_ty.arrayInfo();
20452 const src_info = src_ty.arrayInfo();20796 const src_info = src_ty.arrayInfo();
20453 if (dest_info.len != src_info.len) break :arrays;20797 if (dest_info.len != src_info.len) {
20798 return InMemoryCoercionResult{ .array_len = .{
20799 .actual = src_info.len,
20800 .wanted = dest_info.len,
20801 } };
20802 }
2045420803
20455 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);20804 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
20456 if (child == .no_match) {20805 if (child != .ok) {
20457 return child;20806 return InMemoryCoercionResult{ .array_elem = .{
20807 .child = try child.dupe(sema.arena),
20808 .actual = src_info.elem_type,
20809 .wanted = dest_info.elem_type,
20810 } };
20458 }20811 }
20459 const ok_sent = dest_info.sentinel == null or20812 const ok_sent = dest_info.sentinel == null or
20460 (src_info.sentinel != null and20813 (src_info.sentinel != null and
20461 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod));20814 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod));
20462 if (!ok_sent) {20815 if (!ok_sent) {
20463 return .no_match;20816 return InMemoryCoercionResult{ .array_sentinel = .{
20817 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
20818 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
20819 .ty = dest_info.elem_type,
20820 } };
20464 }20821 }
20465 return .ok;20822 return .ok;
20466 }20823 }
2046720824
20468 // Vectors20825 // Vectors
20469 if (dest_tag == .Vector and src_tag == .Vector) vectors: {20826 if (dest_tag == .Vector and src_tag == .Vector) {
20470 const dest_len = dest_ty.vectorLen();20827 const dest_len = dest_ty.vectorLen();
20471 const src_len = src_ty.vectorLen();20828 const src_len = src_ty.vectorLen();
20472 if (dest_len != src_len) break :vectors;20829 if (dest_len != src_len) {
20830 return InMemoryCoercionResult{ .vector_len = .{
20831 .actual = src_len,
20832 .wanted = dest_len,
20833 } };
20834 }
2047320835
20474 const dest_elem_ty = dest_ty.scalarType();20836 const dest_elem_ty = dest_ty.scalarType();
20475 const src_elem_ty = src_ty.scalarType();20837 const src_elem_ty = src_ty.scalarType();
20476 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);20838 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
20477 if (child == .no_match) break :vectors;20839 if (child != .ok) {
20840 return InMemoryCoercionResult{ .vector_elem = .{
20841 .child = try child.dupe(sema.arena),
20842 .actual = src_elem_ty,
20843 .wanted = dest_elem_ty,
20844 } };
20845 }
2047820846
20479 return .ok;20847 return .ok;
20480 }20848 }
2048120849
20482 // Optionals20850 // Optionals
20483 if (dest_tag == .Optional and src_tag == .Optional) optionals: {20851 if (dest_tag == .Optional and src_tag == .Optional) {
20484 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {20852 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {
20485 // TODO "optional type child '{}' cannot cast into optional type '{}'"20853 return InMemoryCoercionResult{ .optional_shape = .{
20486 return .no_match;20854 .actual = src_ty,
20855 .wanted = dest_ty,
20856 } };
20487 }20857 }
20488 const dest_child_type = dest_ty.optionalChild(&dest_buf);20858 const dest_child_type = dest_ty.optionalChild(&dest_buf);
20489 const src_child_type = src_ty.optionalChild(&src_buf);20859 const src_child_type = src_ty.optionalChild(&src_buf);
2049020860
20491 const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);20861 const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);
20492 if (child == .no_match) {20862 if (child != .ok) {
20493 // TODO "optional type child '{}' cannot cast into optional type child '{}'"20863 return InMemoryCoercionResult{ .optional_child = .{
20494 break :optionals;20864 .child = try child.dupe(sema.arena),
20865 .actual = src_child_type,
20866 .wanted = dest_child_type,
20867 } };
20495 }20868 }
2049620869
20497 return .ok;20870 return .ok;
20498 }20871 }
2049920872
20500 return .no_match;20873 return InMemoryCoercionResult{ .no_match = .{
20874 .actual = dest_ty,
20875 .wanted = src_ty,
20876 } };
20501}20877}
2050220878
20503fn coerceInMemoryAllowedErrorSets(20879fn coerceInMemoryAllowedErrorSets(
...@@ -20564,6 +20940,9 @@ fn coerceInMemoryAllowedErrorSets(...@@ -20564,6 +20940,9 @@ fn coerceInMemoryAllowedErrorSets(
20564 }20940 }
20565 }20941 }
2056620942
20943 var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa);
20944 defer missing_error_buf.deinit();
20945
20567 switch (src_ty.tag()) {20946 switch (src_ty.tag()) {
20568 .error_set_inferred => {20947 .error_set_inferred => {
20569 const src_data = src_ty.castTag(.error_set_inferred).?.data;20948 const src_data = src_ty.castTag(.error_set_inferred).?.data;
...@@ -20572,15 +20951,21 @@ fn coerceInMemoryAllowedErrorSets(...@@ -20572,15 +20951,21 @@ fn coerceInMemoryAllowedErrorSets(
20572 // src anyerror status might have changed after the resolution.20951 // src anyerror status might have changed after the resolution.
20573 if (src_ty.isAnyError()) {20952 if (src_ty.isAnyError()) {
20574 // dest_ty.isAnyError() == true is already checked for at this point.20953 // dest_ty.isAnyError() == true is already checked for at this point.
20575 return .no_match;20954 return .from_anyerror;
20576 }20955 }
2057720956
20578 for (src_data.errors.keys()) |key| {20957 for (src_data.errors.keys()) |key| {
20579 if (!dest_ty.errorSetHasField(key)) {20958 if (!dest_ty.errorSetHasField(key)) {
20580 return .no_match;20959 try missing_error_buf.append(key);
20581 }20960 }
20582 }20961 }
2058320962
20963 if (missing_error_buf.items.len != 0) {
20964 return InMemoryCoercionResult{
20965 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
20966 };
20967 }
20968
20584 return .ok;20969 return .ok;
20585 },20970 },
20586 .error_set_single => {20971 .error_set_single => {
...@@ -20588,37 +20973,52 @@ fn coerceInMemoryAllowedErrorSets(...@@ -20588,37 +20973,52 @@ fn coerceInMemoryAllowedErrorSets(
20588 if (dest_ty.errorSetHasField(name)) {20973 if (dest_ty.errorSetHasField(name)) {
20589 return .ok;20974 return .ok;
20590 }20975 }
20976 const list = try sema.arena.alloc([]const u8, 1);
20977 list[0] = name;
20978 return InMemoryCoercionResult{ .missing_error = list };
20591 },20979 },
20592 .error_set_merged => {20980 .error_set_merged => {
20593 const names = src_ty.castTag(.error_set_merged).?.data.keys();20981 const names = src_ty.castTag(.error_set_merged).?.data.keys();
20594 for (names) |name| {20982 for (names) |name| {
20595 if (!dest_ty.errorSetHasField(name)) {20983 if (!dest_ty.errorSetHasField(name)) {
20596 return .no_match;20984 try missing_error_buf.append(name);
20597 }20985 }
20598 }20986 }
2059920987
20988 if (missing_error_buf.items.len != 0) {
20989 return InMemoryCoercionResult{
20990 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
20991 };
20992 }
20993
20600 return .ok;20994 return .ok;
20601 },20995 },
20602 .error_set => {20996 .error_set => {
20603 const names = src_ty.castTag(.error_set).?.data.names.keys();20997 const names = src_ty.castTag(.error_set).?.data.names.keys();
20604 for (names) |name| {20998 for (names) |name| {
20605 if (!dest_ty.errorSetHasField(name)) {20999 if (!dest_ty.errorSetHasField(name)) {
20606 return .no_match;21000 try missing_error_buf.append(name);
20607 }21001 }
20608 }21002 }
2060921003
21004 if (missing_error_buf.items.len != 0) {
21005 return InMemoryCoercionResult{
21006 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
21007 };
21008 }
21009
20610 return .ok;21010 return .ok;
20611 },21011 },
20612 .anyerror => switch (dest_ty.tag()) {21012 .anyerror => switch (dest_ty.tag()) {
20613 .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above.21013 .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above.
20614 .error_set_single, .error_set_merged, .error_set => {},21014 .error_set_single, .error_set_merged, .error_set => return .from_anyerror,
20615 .anyerror => unreachable, // Filtered out above.21015 .anyerror => unreachable, // Filtered out above.
20616 else => unreachable,21016 else => unreachable,
20617 },21017 },
20618 else => unreachable,21018 else => unreachable,
20619 }21019 }
2062021020
20621 return .no_match;21021 unreachable;
20622}21022}
2062321023
20624fn coerceInMemoryAllowedFns(21024fn coerceInMemoryAllowedFns(
...@@ -20634,44 +21034,67 @@ fn coerceInMemoryAllowedFns(...@@ -20634,44 +21034,67 @@ fn coerceInMemoryAllowedFns(
20634 const src_info = src_ty.fnInfo();21034 const src_info = src_ty.fnInfo();
2063521035
20636 if (dest_info.is_var_args != src_info.is_var_args) {21036 if (dest_info.is_var_args != src_info.is_var_args) {
20637 return .no_match;21037 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
20638 }21038 }
2063921039
20640 if (dest_info.is_generic != src_info.is_generic) {21040 if (dest_info.is_generic != src_info.is_generic) {
20641 return .no_match;21041 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
21042 }
21043
21044 if (dest_info.cc != src_info.cc) {
21045 return InMemoryCoercionResult{ .fn_cc = .{
21046 .actual = src_info.cc,
21047 .wanted = dest_info.cc,
21048 } };
20642 }21049 }
2064321050
20644 if (!src_info.return_type.isNoReturn()) {21051 if (!src_info.return_type.isNoReturn()) {
20645 const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);21052 const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);
20646 if (rt == .no_match) {21053 if (rt != .ok) {
20647 return rt;21054 return InMemoryCoercionResult{ .fn_return_type = .{
21055 .child = try rt.dupe(sema.arena),
21056 .actual = src_info.return_type,
21057 .wanted = dest_info.return_type,
21058 } };
20648 }21059 }
20649 }21060 }
2065021061
20651 if (dest_info.param_types.len != src_info.param_types.len) {21062 if (dest_info.param_types.len != src_info.param_types.len) {
20652 return .no_match;21063 return InMemoryCoercionResult{ .fn_param_count = .{
21064 .actual = dest_info.param_types.len,
21065 .wanted = dest_info.param_types.len,
21066 } };
21067 }
21068
21069 if (dest_info.noalias_bits != src_info.noalias_bits) {
21070 return InMemoryCoercionResult{ .fn_param_noalias = .{
21071 .actual = dest_info.noalias_bits,
21072 .wanted = dest_info.noalias_bits,
21073 } };
20653 }21074 }
2065421075
20655 for (dest_info.param_types) |dest_param_ty, i| {21076 for (dest_info.param_types) |dest_param_ty, i| {
20656 const src_param_ty = src_info.param_types[i];21077 const src_param_ty = src_info.param_types[i];
2065721078
20658 if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {21079 if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
20659 return .no_match;21080 return InMemoryCoercionResult{ .fn_param_comptime = .{
21081 .index = i,
21082 .wanted = dest_info.comptime_params[i],
21083 } };
20660 }21084 }
2066121085
20662 // TODO: noalias
20663
20664 // Note: Cast direction is reversed here.21086 // Note: Cast direction is reversed here.
20665 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);21087 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
20666 if (param == .no_match) {21088 if (param != .ok) {
20667 return param;21089 return InMemoryCoercionResult{ .fn_param = .{
21090 .child = try param.dupe(sema.arena),
21091 .actual = src_param_ty,
21092 .wanted = dest_param_ty,
21093 .index = i,
21094 } };
20668 }21095 }
20669 }21096 }
2067021097
20671 if (dest_info.cc != src_info.cc) {
20672 return .no_match;
20673 }
20674
20675 return .ok;21098 return .ok;
20676}21099}
2067721100
...@@ -20690,26 +21113,13 @@ fn coerceInMemoryAllowedPtrs(...@@ -20690,26 +21113,13 @@ fn coerceInMemoryAllowedPtrs(
20690 const dest_info = dest_ptr_ty.ptrInfo().data;21113 const dest_info = dest_ptr_ty.ptrInfo().data;
20691 const src_info = src_ptr_ty.ptrInfo().data;21114 const src_info = src_ptr_ty.ptrInfo().data;
2069221115
20693 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
20694 if (child == .no_match) {
20695 return child;
20696 }
20697
20698 if (dest_info.@"addrspace" != src_info.@"addrspace") {
20699 return .no_match;
20700 }
20701
20702 const ok_sent = dest_info.sentinel == null or src_info.size == .C or
20703 (src_info.sentinel != null and
20704 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
20705 if (!ok_sent) {
20706 return .no_match;
20707 }
20708
20709 const ok_ptr_size = src_info.size == dest_info.size or21116 const ok_ptr_size = src_info.size == dest_info.size or
20710 src_info.size == .C or dest_info.size == .C;21117 src_info.size == .C or dest_info.size == .C;
20711 if (!ok_ptr_size) {21118 if (!ok_ptr_size) {
20712 return .no_match;21119 return InMemoryCoercionResult{ .ptr_size = .{
21120 .actual = src_info.size,
21121 .wanted = dest_info.size,
21122 } };
20713 }21123 }
2071421124
20715 const ok_cv_qualifiers =21125 const ok_cv_qualifiers =
...@@ -20717,7 +21127,28 @@ fn coerceInMemoryAllowedPtrs(...@@ -20717,7 +21127,28 @@ fn coerceInMemoryAllowedPtrs(
20717 (!src_info.@"volatile" or dest_info.@"volatile");21127 (!src_info.@"volatile" or dest_info.@"volatile");
2071821128
20719 if (!ok_cv_qualifiers) {21129 if (!ok_cv_qualifiers) {
20720 return .no_match;21130 return InMemoryCoercionResult{ .ptr_qualifiers = .{
21131 .actual_const = !src_info.mutable,
21132 .wanted_const = !dest_info.mutable,
21133 .actual_volatile = src_info.@"volatile",
21134 .wanted_volatile = dest_info.@"volatile",
21135 } };
21136 }
21137
21138 if (dest_info.@"addrspace" != src_info.@"addrspace") {
21139 return InMemoryCoercionResult{ .ptr_addrspace = .{
21140 .actual = src_info.@"addrspace",
21141 .wanted = dest_info.@"addrspace",
21142 } };
21143 }
21144
21145 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
21146 if (child != .ok) {
21147 return InMemoryCoercionResult{ .ptr_child = .{
21148 .child = try child.dupe(sema.arena),
21149 .actual = src_info.pointee_type,
21150 .wanted = dest_info.pointee_type,
21151 } };
20721 }21152 }
2072221153
20723 const dest_allow_zero = dest_ty.ptrAllowsZero();21154 const dest_allow_zero = dest_ty.ptrAllowsZero();
...@@ -20727,13 +21158,32 @@ fn coerceInMemoryAllowedPtrs(...@@ -20727,13 +21158,32 @@ fn coerceInMemoryAllowedPtrs(
20727 (src_allow_zero or !dest_is_mut)) or21158 (src_allow_zero or !dest_is_mut)) or
20728 (!dest_allow_zero and !src_allow_zero);21159 (!dest_allow_zero and !src_allow_zero);
20729 if (!ok_allows_zero) {21160 if (!ok_allows_zero) {
20730 return .no_match;21161 return InMemoryCoercionResult{ .ptr_allowzero = .{
21162 .actual = src_ty,
21163 .wanted = dest_ty,
21164 } };
20731 }21165 }
2073221166
20733 if (src_info.host_size != dest_info.host_size or21167 if (src_info.host_size != dest_info.host_size or
20734 src_info.bit_offset != dest_info.bit_offset)21168 src_info.bit_offset != dest_info.bit_offset)
20735 {21169 {
20736 return .no_match;21170 return InMemoryCoercionResult{ .ptr_bit_range = .{
21171 .actual_host = src_info.host_size,
21172 .wanted_host = dest_info.host_size,
21173 .actual_offset = src_info.bit_offset,
21174 .wanted_offset = dest_info.bit_offset,
21175 } };
21176 }
21177
21178 const ok_sent = dest_info.sentinel == null or src_info.size == .C or
21179 (src_info.sentinel != null and
21180 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
21181 if (!ok_sent) {
21182 return InMemoryCoercionResult{ .ptr_sentinel = .{
21183 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
21184 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
21185 .ty = dest_info.pointee_type,
21186 } };
20737 }21187 }
2073821188
20739 // If both pointers have alignment 0, it means they both want ABI alignment.21189 // If both pointers have alignment 0, it means they both want ABI alignment.
...@@ -20758,7 +21208,10 @@ fn coerceInMemoryAllowedPtrs(...@@ -20758,7 +21208,10 @@ fn coerceInMemoryAllowedPtrs(
20758 dest_info.pointee_type.abiAlignment(target);21208 dest_info.pointee_type.abiAlignment(target);
2075921209
20760 if (dest_align > src_align) {21210 if (dest_align > src_align) {
20761 return .no_match;21211 return InMemoryCoercionResult{ .ptr_alignment = .{
21212 .actual = src_align,
21213 .wanted = dest_align,
21214 } };
20762 }21215 }
2076321216
20764 break :alignment;21217 break :alignment;
test/cases/compile_errors/address_of_number_literal.zig+1
...@@ -8,3 +8,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }...@@ -8,3 +8,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
8// target=native8// target=native
9//9//
10// :3:30: error: expected type '*const i32', found '*const comptime_int'10// :3:30: error: expected type '*const i32', found '*const comptime_int'
11// :3:30: note: pointer type child 'comptime_int' cannot cast into pointer type child 'i32'
test/cases/compile_errors/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig created+14
...@@ -0,0 +1,14 @@
1export fn entry(byte: u8) void {
2 const w: i32 = 1234;
3 var x: *const i32 = &w;
4 var y: *[1]i32 = x;
5 y[0] += 1;
6 _ = byte;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :4:22: error: expected type '*[1]i32', found '*const i32'
14// :4:22: note: cast discards const qualifier
test/cases/compile_errors/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig created+15
...@@ -0,0 +1,15 @@
1const SmallErrorSet = error{A};
2export fn entry() void {
3 var x: SmallErrorSet!i32 = foo();
4 _ = x;
5}
6fn foo() anyerror!i32 {
7 return error.B;
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :3:35: error: expected type 'error{A}!i32', found 'anyerror!i32'
15// :3:35: note: global error set cannot cast into a smaller set
test/cases/compile_errors/cast_global_error_set_to_error_set.zig created+15
...@@ -0,0 +1,15 @@
1const SmallErrorSet = error{A};
2export fn entry() void {
3 var x: SmallErrorSet = foo();
4 _ = x;
5}
6fn foo() anyerror {
7 return error.B;
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :3:31: error: expected type 'error{A}', found 'anyerror'
15// :3:31: note: global error set cannot cast into a smaller set
test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig+2
...@@ -19,3 +19,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }...@@ -19,3 +19,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
19// target=native19// target=native
20//20//
21// :8:15: error: expected type '*const u3', found '*align(0:3:1) const u3'21// :8:15: error: expected type '*const u3', found '*align(0:3:1) const u3'
22// :8:15: note: pointer host size '1' cannot cast into pointer host size '0'
23// :8:15: note: pointer bit offset '3' cannot cast into pointer bit offset '0'
test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig+1
...@@ -11,3 +11,4 @@ export fn entry() void {...@@ -11,3 +11,4 @@ export fn entry() void {
11// target=native11// target=native
12//12//
13// :5:28: error: expected type '*anyopaque', found '**u32'13// :5:28: error: expected type '*anyopaque', found '**u32'
14// :5:28: note: pointer type child '*u32' cannot cast into pointer type child 'anyopaque'
test/cases/compile_errors/error_note_for_function_parameter_incompatibility.zig created+13
...@@ -0,0 +1,13 @@
1fn do_the_thing(func: *const fn (arg: i32) void) void { _ = func; }
2fn bar(arg: bool) void { _ = arg; }
3export fn entry() void {
4 do_the_thing(bar);
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :4:17: error: expected type '*const fn(i32) void', found '*const fn(bool) void'
12// :4:17: note: pointer type child 'fn(bool) void' cannot cast into pointer type child 'fn(i32) void'
13// :4:17: note: parameter 0 'bool' cannot cast into 'i32'
test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig created+16
...@@ -0,0 +1,16 @@
1const Set1 = error{A, B};
2const Set2 = error{A, C};
3export fn entry() void {
4 foo(Set1.B);
5}
6fn foo(set1: Set1) void {
7 var x: Set2 = set1;
8 _ = x;
9}
10
11// error
12// backend=stage2
13// target=native
14//
15// :7:19: error: expected type 'error{A,C}', found 'error{A,B}'
16// :7:19: note: 'error.B' not a member of destination error set
test/cases/compile_errors/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig created+26
...@@ -0,0 +1,26 @@
1export fn entry() void {
2 var slice: []const u8 = "aoeu";
3 const opt_many_ptr: [*]const u8 = slice.ptr;
4 var ptr_opt_many_ptr = &opt_many_ptr;
5 var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
6 ptr_opt_many_ptr = c_ptr;
7}
8export fn entry2() void {
9 var buf: [4]u8 = "aoeu".*;
10 var slice: []u8 = &buf;
11 var opt_many_ptr: [*]u8 = slice.ptr;
12 var ptr_opt_many_ptr = &opt_many_ptr;
13 var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
14 _ = c_ptr;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'
22// :6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'
23// :6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'
24// :13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'
25// :13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'
26// :13:35: note: mutable '[*]u8' allows illegal null values stored to type '[*c]const u8'
test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig+1
...@@ -15,3 +15,4 @@ export fn entry() void {...@@ -15,3 +15,4 @@ export fn entry() void {
15// target=native15// target=native
16//16//
17// :9:22: error: expected type 'u2', found 'tmp.Small'17// :9:22: error: expected type 'u2', found 'tmp.Small'
18// :1:15: note: enum declared here
test/cases/compile_errors/incompatible_sentinels.zig created+29
...@@ -0,0 +1,29 @@
1// Note: One of the error messages here is backwards. It would be nice to fix, but that's not
2// going to stop me from merging this branch which fixes a bunch of other stuff.
3export fn entry1(ptr: [*:255]u8) [*:0]u8 {
4 return ptr;
5}
6export fn entry2(ptr: [*]u8) [*:0]u8 {
7 return ptr;
8}
9export fn entry3() void {
10 var array: [2:0]u8 = [_:255]u8{ 1, 2 };
11 _ = array;
12}
13export fn entry4() void {
14 var array: [2:0]u8 = [_]u8{ 1, 2 };
15 _ = array;
16}
17
18// error
19// backend=stage2
20// target=native
21//
22// :4:12: error: expected type '[*:0]u8', found '[*:255]u8'
23// :4:12: note: pointer sentinel '255' cannot cast into pointer sentinel '0'
24// :7:12: error: expected type '[*:0]u8', found '[*]u8'
25// :7:12: note: destination pointer requires '0' sentinel
26// :10:35: error: expected type '[2:0]u8', found '[2:255]u8'
27// :10:35: note: array sentinel '255' cannot cast into array sentinel '0'
28// :14:31: error: expected type '[2:0]u8', found '[2]u8'
29// :14:31: note: destination array requires '0' sentinel
test/cases/compile_errors/incorrect_return_type.zig+2
...@@ -19,3 +19,5 @@...@@ -19,3 +19,5 @@
19// target=native19// target=native
20//20//
21// :8:16: error: expected type 'tmp.A', found 'tmp.B'21// :8:16: error: expected type 'tmp.A', found 'tmp.B'
22// :10:12: note: struct declared here
23// :4:12: note: struct declared here
test/cases/compile_errors/invalid_address_space_coercion.zig+1
...@@ -11,3 +11,4 @@ pub fn main() void {...@@ -11,3 +11,4 @@ pub fn main() void {
11// target=x86_64-linux,x86_64-macos11// target=x86_64-linux,x86_64-macos
12//12//
13// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'13// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:12: note: address space 'gs' cannot cast into address space 'generic'
test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig+1
...@@ -15,3 +15,4 @@ fn foo(x: usize) void {...@@ -15,3 +15,4 @@ fn foo(x: usize) void {
15// target=native15// target=native
16//16//
17// :9:10: error: expected type 'usize', found 'tmp.E'17// :9:10: error: expected type 'usize', found 'tmp.E'
18// :1:11: note: enum declared here
test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig+1
...@@ -11,3 +11,4 @@ pub fn main() void {...@@ -11,3 +11,4 @@ pub fn main() void {
11// target=x86_64-linux,x86_64-macos11// target=x86_64-linux,x86_64-macos
12//12//
13// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'13// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:12: note: address space 'gs' cannot cast into address space 'generic'
test/cases/compile_errors/not_an_enum_type.zig+1
...@@ -17,3 +17,4 @@ const ExpectedVarDeclOrFn = struct {};...@@ -17,3 +17,4 @@ const ExpectedVarDeclOrFn = struct {};
17// target=native17// target=native
18//18//
19// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'19// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'
20// :8:1: note: enum declared here
test/cases/compile_errors/passing_a_not-aligned-enough_pointer_to_cmpxchg.zig+1
...@@ -10,3 +10,4 @@ export fn entry() bool {...@@ -10,3 +10,4 @@ export fn entry() bool {
10// target=native10// target=native
11//11//
12// :4:31: error: expected type '*i32', found '*align(1) i32'12// :4:31: error: expected type '*i32', found '*align(1) i32'
13// :4:31: note: pointer alignment '1' cannot cast into pointer alignment '4'
test/cases/compile_errors/pointer_with_different_address_spaces.zig+1
...@@ -11,3 +11,4 @@ export fn entry2() void {...@@ -11,3 +11,4 @@ export fn entry2() void {
11// target=x86_64-linux,x86_64-macos11// target=x86_64-linux,x86_64-macos
12//12//
13// :2:12: error: expected type '*addrspace(.fs) i32', found '*addrspace(.gs) i32'13// :2:12: error: expected type '*addrspace(.fs) i32', found '*addrspace(.gs) i32'
14// :2:12: note: address space 'gs' cannot cast into address space 'fs'
test/cases/compile_errors/pointers_with_different_address_spaces.zig+1
...@@ -11,3 +11,4 @@ pub fn main() void {...@@ -11,3 +11,4 @@ pub fn main() void {
11// target=x86_64-linux,x86_64-macos11// target=x86_64-linux,x86_64-macos
12//12//
13// :2:13: error: expected type '*i32', found '*addrspace(.gs) i32'13// :2:13: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:13: note: address space 'gs' cannot cast into address space 'generic'
test/cases/compile_errors/shifting_RHS_is_log2_of_LHS_int_bit_width.zig+1
...@@ -7,3 +7,4 @@ export fn entry(x: u8, y: u8) u8 {...@@ -7,3 +7,4 @@ export fn entry(x: u8, y: u8) u8 {
7// target=native7// target=native
8//8//
9// :2:17: error: expected type 'u3', found 'u8'9// :2:17: error: expected type 'u3', found 'u8'
10// :2:17: note: unsigned 3-bit int cannot represent all possible unsigned 8-bit values
test/cases/compile_errors/slice_sentinel_mismatch-2.zig created+12
...@@ -0,0 +1,12 @@
1fn foo() [:0]u8 {
2 var x: []u8 = undefined;
3 return x;
4}
5comptime { _ = foo; }
6
7// error
8// backend=stage2
9// target=native
10//
11// :3:12: error: expected type '[:0]u8', found '[]u8'
12// :3:12: note: destination pointer requires '0' sentinel
test/cases/compile_errors/stage1/obj/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig deleted-14
...@@ -1,14 +0,0 @@
1export fn entry(byte: u8) void {
2 const w: i32 = 1234;
3 var x: *const i32 = &w;
4 var y: *[1]i32 = x;
5 y[0] += 1;
6 _ = byte;
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'
14// tmp.zig:4:22: note: cast discards const qualifier
test/cases/compile_errors/stage1/obj/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig deleted-16
...@@ -1,16 +0,0 @@
1const SmallErrorSet = error{A};
2export fn entry() void {
3 var x: SmallErrorSet!i32 = foo();
4 _ = x;
5}
6fn foo() anyerror!i32 {
7 return error.B;
8}
9
10// error
11// backend=stage1
12// target=native
13//
14// tmp.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32'
15// tmp.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet'
16// tmp.zig:3:35: note: cannot cast global error set into smaller set
test/cases/compile_errors/stage1/obj/cast_global_error_set_to_error_set.zig deleted-15
...@@ -1,15 +0,0 @@
1const SmallErrorSet = error{A};
2export fn entry() void {
3 var x: SmallErrorSet = foo();
4 _ = x;
5}
6fn foo() anyerror {
7 return error.B;
8}
9
10// error
11// backend=stage1
12// target=native
13//
14// tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror'
15// tmp.zig:3:31: note: cannot cast global error set into smaller set
test/cases/compile_errors/stage1/obj/error_note_for_function_parameter_incompatibility.zig deleted-12
...@@ -1,12 +0,0 @@
1fn do_the_thing(func: fn (arg: i32) void) void { _ = func; }
2fn bar(arg: bool) void { _ = arg; }
3export fn entry() void {
4 do_the_thing(bar);
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void
12// tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'
test/cases/compile_errors/stage1/obj/implicit_cast_of_error_set_not_a_subset.zig deleted-16
...@@ -1,16 +0,0 @@
1const Set1 = error{A, B};
2const Set2 = error{A, C};
3export fn entry() void {
4 foo(Set1.B);
5}
6fn foo(set1: Set1) void {
7 var x: Set2 = set1;
8 _ = x;
9}
10
11// error
12// backend=stage1
13// target=native
14//
15// tmp.zig:7:19: error: expected type 'Set2', found 'Set1'
16// tmp.zig:1:23: note: 'error.B' not a member of destination error set
test/cases/compile_errors/stage1/obj/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig deleted-26
...@@ -1,26 +0,0 @@
1export fn entry() void {
2 var slice: []const u8 = "aoeu";
3 const opt_many_ptr: [*]const u8 = slice.ptr;
4 var ptr_opt_many_ptr = &opt_many_ptr;
5 var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
6 ptr_opt_many_ptr = c_ptr;
7}
8export fn entry2() void {
9 var buf: [4]u8 = "aoeu".*;
10 var slice: []u8 = &buf;
11 var opt_many_ptr: [*]u8 = slice.ptr;
12 var ptr_opt_many_ptr = &opt_many_ptr;
13 var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
14 _ = c_ptr;
15}
16
17// error
18// backend=stage1
19// target=native
20//
21// tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'
22// tmp.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'
23// tmp.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'
24// tmp.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'
25// tmp.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'
26// tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'
test/cases/compile_errors/stage1/obj/incompatible_sentinels.zig deleted-29
...@@ -1,29 +0,0 @@
1// Note: One of the error messages here is backwards. It would be nice to fix, but that's not
2// going to stop me from merging this branch which fixes a bunch of other stuff.
3export fn entry1(ptr: [*:255]u8) [*:0]u8 {
4 return ptr;
5}
6export fn entry2(ptr: [*]u8) [*:0]u8 {
7 return ptr;
8}
9export fn entry3() void {
10 var array: [2:0]u8 = [_:255]u8{ 1, 2 };
11 _ = array;
12}
13export fn entry4() void {
14 var array: [2:0]u8 = [_]u8{ 1, 2 };
15 _ = array;
16}
17
18// error
19// backend=stage1
20// target=native
21//
22// tmp.zig:4:12: error: expected type '[*:0]u8', found '[*:255]u8'
23// tmp.zig:4:12: note: destination pointer requires a terminating '0' sentinel, but source pointer has a terminating '255' sentinel
24// tmp.zig:7:12: error: expected type '[*:0]u8', found '[*]u8'
25// tmp.zig:7:12: note: destination pointer requires a terminating '0' sentinel
26// tmp.zig:10:35: error: expected type '[2:255]u8', found '[2:0]u8'
27// tmp.zig:10:35: note: destination array requires a terminating '255' sentinel, but source array has a terminating '0' sentinel
28// tmp.zig:14:31: error: expected type '[2:0]u8', found '[2]u8'
29// tmp.zig:14:31: note: destination array requires a terminating '0' sentinel
test/cases/compile_errors/stage1/obj/slice_sentinel_mismatch-2.zig deleted-12
...@@ -1,12 +0,0 @@
1fn foo() [:0]u8 {
2 var x: []u8 = undefined;
3 return x;
4}
5comptime { _ = foo; }
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:12: error: expected type '[:0]u8', found '[]u8'
12// tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel
test/cases/compile_errors/stage1/obj/type_checking_function_pointers.zig deleted-13
...@@ -1,13 +0,0 @@
1fn a(b: fn (*const u8) void) void {
2 b('a');
3}
4fn c(d: u8) void {_ = d;}
5export fn entry() void {
6 a(c);
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:6:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void'
test/cases/compile_errors/type_checking_function_pointers.zig created+15
...@@ -0,0 +1,15 @@
1fn a(b: *const fn (*const u8) void) void {
2 _ = b;
3}
4fn c(d: u8) void {_ = d;}
5export fn entry() void {
6 a(c);
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :6:6: error: expected type '*const fn(*const u8) void', found '*const fn(u8) void'
14// :6:6: note: pointer type child 'fn(u8) void' cannot cast into pointer type child 'fn(*const u8) void'
15// :6:6: note: parameter 0 'u8' cannot cast into '*const u8'
test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig+2
...@@ -11,3 +11,5 @@ export fn main() void {...@@ -11,3 +11,5 @@ export fn main() void {
11// target=native11// target=native
12//12//
13// :5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'13// :5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'
14// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8'
15// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8'
test/cases/compile_errors/wrong_type_for_reify_type.zig+1
...@@ -7,3 +7,4 @@ export fn entry() void {...@@ -7,3 +7,4 @@ export fn entry() void {
7// target=native7// target=native
8//8//
9// :2:15: error: expected type 'builtin.Type', found 'comptime_int'9// :2:15: error: expected type 'builtin.Type', found 'comptime_int'
10// :?:?: note: union declared here