authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-11 20:45:27-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-11 20:45:27-04:00
log7d2e14267985df0226a5deee96d0c17c94bf6eb2
tree7ed0b99d42c983c1ed2246d0094600a9425c65c0
parentdc815e5e8f194a03988624a6bf7e739ddfe0d3b4
parent20d4f7213dde1ffabe0880bbee46a1de44d586fc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12044 from Vexu/stage2-compile-errors

Sema: add detailed error notes to `coerceInMemoryAllowed`

60 files changed, 1072 insertions(+), 401 deletions(-)

lib/std/zig.zig+4
......@@ -49,6 +49,10 @@ pub const Loc = struct {
4949 column: usize,
5050 /// Does not include the trailing newline.
5151 source_line: []const u8,
52
53 pub fn eql(a: Loc, b: Loc) bool {
54 return a.line == b.line and a.column == b.column and std.mem.eql(u8, a.source_line, b.source_line);
55 }
5256};
5357
5458pub fn findLineColumn(source: []const u8, byte_offset: usize) Loc {
src/Compilation.zig+23-24
......@@ -526,6 +526,9 @@ pub const AllErrors = struct {
526526 Message.HashContext,
527527 std.hash_map.default_max_load_percentage,
528528 ).init(allocator);
529 const err_source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
530 const err_byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
531 const err_loc = std.zig.findLineColumn(err_source.bytes, err_byte_offset);
529532
530533 for (module_err_msg.notes) |module_note| {
531534 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
......@@ -540,7 +543,7 @@ pub const AllErrors = struct {
540543 .byte_offset = byte_offset,
541544 .line = @intCast(u32, loc.line),
542545 .column = @intCast(u32, loc.column),
543 .source_line = try allocator.dupe(u8, loc.source_line),
546 .source_line = if (err_loc.eql(loc)) null else try allocator.dupe(u8, loc.source_line),
544547 },
545548 };
546549 const gop = try seen_notes.getOrPut(note);
......@@ -558,19 +561,16 @@ pub const AllErrors = struct {
558561 });
559562 return;
560563 }
561 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
562 const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
563 const loc = std.zig.findLineColumn(source.bytes, byte_offset);
564564 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator);
565565 try errors.append(.{
566566 .src = .{
567567 .src_path = file_path,
568568 .msg = try allocator.dupe(u8, module_err_msg.msg),
569 .byte_offset = byte_offset,
570 .line = @intCast(u32, loc.line),
571 .column = @intCast(u32, loc.column),
569 .byte_offset = err_byte_offset,
570 .line = @intCast(u32, err_loc.line),
571 .column = @intCast(u32, err_loc.column),
572572 .notes = notes_buf[0..note_i],
573 .source_line = try allocator.dupe(u8, loc.source_line),
573 .source_line = try allocator.dupe(u8, err_loc.source_line),
574574 },
575575 });
576576 }
......@@ -593,6 +593,16 @@ pub const AllErrors = struct {
593593 while (item_i < items_len) : (item_i += 1) {
594594 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
595595 extra_index = item.end;
596 const err_byte_offset = blk: {
597 const token_starts = file.tree.tokens.items(.start);
598 if (item.data.node != 0) {
599 const main_tokens = file.tree.nodes.items(.main_token);
600 const main_token = main_tokens[item.data.node];
601 break :blk token_starts[main_token];
602 }
603 break :blk token_starts[item.data.token] + item.data.byte_offset;
604 };
605 const err_loc = std.zig.findLineColumn(file.source, err_byte_offset);
596606
597607 var notes: []Message = &[0]Message{};
598608 if (item.data.notes != 0) {
......@@ -621,33 +631,22 @@ pub const AllErrors = struct {
621631 .line = @intCast(u32, loc.line),
622632 .column = @intCast(u32, loc.column),
623633 .notes = &.{}, // TODO rework this function to be recursive
624 .source_line = try arena.dupe(u8, loc.source_line),
634 .source_line = if (loc.eql(err_loc)) null else try arena.dupe(u8, loc.source_line),
625635 },
626636 };
627637 }
628638 }
629639
630640 const msg = file.zir.nullTerminatedString(item.data.msg);
631 const byte_offset = blk: {
632 const token_starts = file.tree.tokens.items(.start);
633 if (item.data.node != 0) {
634 const main_tokens = file.tree.nodes.items(.main_token);
635 const main_token = main_tokens[item.data.node];
636 break :blk token_starts[main_token];
637 }
638 break :blk token_starts[item.data.token] + item.data.byte_offset;
639 };
640 const loc = std.zig.findLineColumn(file.source, byte_offset);
641
642641 try errors.append(.{
643642 .src = .{
644643 .src_path = try file.fullPath(arena),
645644 .msg = try arena.dupe(u8, msg),
646 .byte_offset = byte_offset,
647 .line = @intCast(u32, loc.line),
648 .column = @intCast(u32, loc.column),
645 .byte_offset = err_byte_offset,
646 .line = @intCast(u32, err_loc.line),
647 .column = @intCast(u32, err_loc.column),
649648 .notes = notes,
650 .source_line = try arena.dupe(u8, loc.source_line),
649 .source_line = try arena.dupe(u8, err_loc.source_line),
651650 },
652651 });
653652 }
src/Sema.zig+684-95
......@@ -2749,7 +2749,15 @@ fn ensureResultUsed(
27492749 const operand_ty = sema.typeOf(operand);
27502750 switch (operand_ty.zigTypeTag()) {
27512751 .Void, .NoReturn => return,
2752 .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is ignored. consider using `try`, `catch`, or `if`", .{}),
2752 .ErrorSet, .ErrorUnion => {
2753 const msg = msg: {
2754 const msg = try sema.errMsg(block, src, "error is ignored", .{});
2755 errdefer msg.destroy(sema.gpa);
2756 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{});
2757 break :msg msg;
2758 };
2759 return sema.failWithOwnedErrorMsg(block, msg);
2760 },
27532761 else => return sema.fail(block, src, "expression value is ignored", .{}),
27542762 }
27552763}
......@@ -2763,7 +2771,15 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
27632771 const src = inst_data.src();
27642772 const operand_ty = sema.typeOf(operand);
27652773 switch (operand_ty.zigTypeTag()) {
2766 .ErrorSet, .ErrorUnion => return sema.fail(block, src, "error is discarded. consider using `try`, `catch`, or `if`", .{}),
2774 .ErrorSet, .ErrorUnion => {
2775 const msg = msg: {
2776 const msg = try sema.errMsg(block, src, "error is discarded", .{});
2777 errdefer msg.destroy(sema.gpa);
2778 try sema.errNote(block, src, msg, "consider using `try`, `catch`, or `if`", .{});
2779 break :msg msg;
2780 };
2781 return sema.failWithOwnedErrorMsg(block, msg);
2782 },
27672783 else => return,
27682784 }
27692785}
......@@ -4119,23 +4135,24 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
41194135 const ptr = try sema.resolveInst(extra.lhs);
41204136 const operand = try sema.resolveInst(extra.rhs);
41214137
4138 const is_ret = if (Zir.refToIndex(extra.lhs)) |ptr_index|
4139 zir_tags[ptr_index] == .ret_ptr
4140 else
4141 false;
4142
41224143 // Check for the possibility of this pattern:
41234144 // %a = ret_ptr
41244145 // %b = store(%a, %c)
41254146 // Where %c is an error union or error set. In such case we need to add
41264147 // to the current function's inferred error set, if any.
4127 if ((sema.typeOf(operand).zigTypeTag() == .ErrorUnion or
4148 if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or
41284149 sema.typeOf(operand).zigTypeTag() == .ErrorSet) and
41294150 sema.fn_ret_ty.zigTypeTag() == .ErrorUnion)
41304151 {
4131 if (Zir.refToIndex(extra.lhs)) |ptr_index| {
4132 if (zir_tags[ptr_index] == .ret_ptr) {
4133 try sema.addToInferredErrorSet(operand);
4134 }
4135 }
4152 try sema.addToInferredErrorSet(operand);
41364153 }
41374154
4138 return sema.storePtr(block, src, ptr, operand);
4155 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);
41394156}
41404157
41414158fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -5534,7 +5551,7 @@ fn analyzeCall(
55345551 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
55355552 else
55365553 try sema.resolveInst(fn_info.ret_ty_ref);
5537 const ret_ty_src = func_src; // TODO better source location
5554 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
55385555 const bare_return_type = try sema.analyzeAsType(&child_block, ret_ty_src, ret_ty_inst);
55395556 // Create a fresh inferred error set type for inline/comptime calls.
55405557 const fn_ret_ty = blk: {
......@@ -6876,7 +6893,7 @@ fn zirFunc(
68766893 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
68776894 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
68786895 const target = sema.mod.getTarget();
6879 const ret_ty_src = inst_data.src(); // TODO better source location
6896 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = inst_data.src_node };
68806897
68816898 var extra_index = extra.end;
68826899
......@@ -7458,13 +7475,20 @@ fn analyzeAs(
74587475 zir_dest_type: Zir.Inst.Ref,
74597476 zir_operand: Zir.Inst.Ref,
74607477) CompileError!Air.Inst.Ref {
7478 const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index|
7479 sema.code.instructions.items(.tag)[ptr_index] == .ret_type
7480 else
7481 false;
74617482 const dest_ty = try sema.resolveType(block, src, zir_dest_type);
74627483 const operand = try sema.resolveInst(zir_operand);
74637484 if (dest_ty.tag() == .var_args_param) return operand;
74647485 if (dest_ty.zigTypeTag() == .NoReturn) {
74657486 return sema.fail(block, src, "cannot cast to noreturn", .{});
74667487 }
7467 return sema.coerce(block, dest_ty, operand, src);
7488 return sema.coerceExtra(block, dest_ty, operand, src, true, is_ret) catch |err| switch (err) {
7489 error.NotCoercible => unreachable,
7490 else => |e| return e,
7491 };
74687492}
74697493
74707494fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -13647,7 +13671,10 @@ fn analyzeRet(
1364713671 if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {
1364813672 try sema.addToInferredErrorSet(uncasted_operand);
1364913673 }
13650 const operand = try sema.coerce(block, sema.fn_ret_ty, uncasted_operand, src);
13674 const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, true, true) catch |err| switch (err) {
13675 error.NotCoercible => unreachable,
13676 else => |e| return e,
13677 };
1365113678
1365213679 if (block.inlining) |inlining| {
1365313680 if (block.is_comptime) {
......@@ -19993,6 +20020,27 @@ fn coerce(
1999320020 inst: Air.Inst.Ref,
1999420021 inst_src: LazySrcLoc,
1999520022) CompileError!Air.Inst.Ref {
20023 return sema.coerceExtra(block, dest_ty_unresolved, inst, inst_src, true, false) catch |err| switch (err) {
20024 error.NotCoercible => unreachable,
20025 else => |e| return e,
20026 };
20027}
20028
20029const CoersionError = CompileError || error{
20030 /// When coerce is called recursively, this error should be returned instead of using `fail`
20031 /// to ensure correct types in compile errors.
20032 NotCoercible,
20033};
20034
20035fn coerceExtra(
20036 sema: *Sema,
20037 block: *Block,
20038 dest_ty_unresolved: Type,
20039 inst: Air.Inst.Ref,
20040 inst_src: LazySrcLoc,
20041 report_err: bool,
20042 is_ret: bool,
20043) CoersionError!Air.Inst.Ref {
1999620044 switch (dest_ty_unresolved.tag()) {
1999720045 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
1999820046 .generic_poison => return inst,
......@@ -20009,7 +20057,7 @@ fn coerce(
2000920057 const arena = sema.arena;
2001020058 const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
2001120059
20012 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
20060 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
2001320061 if (in_memory_result == .ok) {
2001420062 if (maybe_inst_val) |val| {
2001520063 // Keep the comptime Value representation; take the new type.
......@@ -20022,7 +20070,7 @@ fn coerce(
2002220070 const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
2002320071
2002420072 switch (dest_ty.zigTypeTag()) {
20025 .Optional => {
20073 .Optional => optional: {
2002620074 // undefined sets the optional bit also to undefined.
2002720075 if (is_undef) {
2002820076 return sema.addConstUndef(dest_ty);
......@@ -20043,10 +20091,19 @@ fn coerce(
2004320091
2004420092 // T to ?T
2004520093 const child_type = try dest_ty.optionalChildAlloc(sema.arena);
20046 const intermediate = try sema.coerce(block, child_type, inst, inst_src);
20047 return sema.wrapOptional(block, dest_ty, intermediate, inst_src);
20094 const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, false, is_ret) catch |err| switch (err) {
20095 error.NotCoercible => {
20096 if (in_memory_result == .no_match) {
20097 // Try to give more useful notes
20098 in_memory_result = try sema.coerceInMemoryAllowed(block, child_type, inst_ty, false, target, dest_ty_src, inst_src);
20099 }
20100 break :optional;
20101 },
20102 else => |e| return e,
20103 };
20104 return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
2004820105 },
20049 .Pointer => {
20106 .Pointer => pointer: {
2005020107 const dest_info = dest_ty.ptrInfo().data;
2005120108
2005220109 // Function body to function pointer.
......@@ -20071,7 +20128,7 @@ fn coerce(
2007120128 if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item;
2007220129 switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
2007320130 .ok => {},
20074 .no_match => break :single_item,
20131 else => break :single_item,
2007520132 }
2007620133 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
2007720134 }
......@@ -20091,7 +20148,7 @@ fn coerce(
2009120148 const dst_elem_type = dest_info.pointee_type;
2009220149 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) {
2009320150 .ok => {},
20094 .no_match => break :src_array_ptr,
20151 else => break :src_array_ptr,
2009520152 }
2009620153
2009720154 switch (dest_info.size) {
......@@ -20130,7 +20187,7 @@ fn coerce(
2013020187 const dst_elem_type = dest_info.pointee_type;
2013120188 switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
2013220189 .ok => {},
20133 .no_match => break :src_c_ptr,
20190 else => break :src_c_ptr,
2013420191 }
2013520192 // TODO add safety check for null pointer
2013620193 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
......@@ -20151,16 +20208,26 @@ fn coerce(
2015120208 return sema.addConstant(dest_ty, Value.@"null");
2015220209 },
2015320210 .ComptimeInt => {
20154 const addr = try sema.coerce(block, Type.usize, inst, inst_src);
20155 return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
20211 const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, false, is_ret) catch |err| switch (err) {
20212 error.NotCoercible => break :pointer,
20213 else => |e| return e,
20214 };
20215 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
2015620216 },
2015720217 .Int => {
2015820218 const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
2015920219 .signed => Type.isize,
2016020220 .unsigned => Type.usize,
2016120221 };
20162 const addr = try sema.coerce(block, ptr_size_ty, inst, inst_src);
20163 return sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
20222 const addr = sema.coerceExtra(block, ptr_size_ty, inst, inst_src, false, is_ret) catch |err| switch (err) {
20223 error.NotCoercible => {
20224 // Try to give more useful notes
20225 in_memory_result = try sema.coerceInMemoryAllowed(block, ptr_size_ty, inst_ty, false, target, dest_ty_src, inst_src);
20226 break :pointer;
20227 },
20228 else => |e| return e,
20229 };
20230 return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
2016420231 },
2016520232 .Pointer => p: {
2016620233 const inst_info = inst_ty.ptrInfo().data;
......@@ -20174,7 +20241,7 @@ fn coerce(
2017420241 inst_src,
2017520242 )) {
2017620243 .ok => {},
20177 .no_match => break :p,
20244 else => break :p,
2017820245 }
2017920246 if (inst_info.size == .Slice) {
2018020247 if (dest_info.sentinel == null or inst_info.sentinel == null or
......@@ -20264,7 +20331,7 @@ fn coerce(
2026420331 inst_src,
2026520332 )) {
2026620333 .ok => {},
20267 .no_match => break :p,
20334 else => break :p,
2026820335 }
2026920336
2027020337 if (dest_info.sentinel == null or inst_info.sentinel == null or
......@@ -20295,6 +20362,7 @@ fn coerce(
2029520362 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
2029620363 // comptime known integer to other number
2029720364 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
20365 if (!report_err) return error.NotCoercible;
2029820366 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
2029920367 }
2030020368 return try sema.addConstant(dest_ty, val);
......@@ -20496,14 +20564,396 @@ fn coerce(
2049620564 return sema.addConstUndef(dest_ty);
2049720565 }
2049820566
20499 return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
20567 if (!report_err) return error.NotCoercible;
20568
20569 if (is_ret and dest_ty.zigTypeTag() == .NoReturn) {
20570 const msg = msg: {
20571 const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
20572 errdefer msg.destroy(sema.gpa);
20573
20574 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
20575 const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
20576 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{});
20577 break :msg msg;
20578 };
20579 return sema.failWithOwnedErrorMsg(block, msg);
20580 }
20581
20582 const msg = msg: {
20583 const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
20584 errdefer msg.destroy(sema.gpa);
20585
20586 // E!T to T
20587 if (inst_ty.zigTypeTag() == .ErrorUnion and
20588 (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
20589 {
20590 try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
20591 try sema.errNote(block, inst_src, msg, "consider using `try`, `catch`, or `if`", .{});
20592 }
20593
20594 // ?T to T
20595 var buf: Type.Payload.ElemType = undefined;
20596 if (inst_ty.zigTypeTag() == .Optional and
20597 (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
20598 {
20599 try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
20600 try sema.errNote(block, inst_src, msg, "consider using `.?`, `orelse`, or `if`", .{});
20601 }
20602
20603 try in_memory_result.report(sema, block, inst_src, msg);
20604
20605 // Add notes about function return type
20606 if (is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) {
20607 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
20608 const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
20609 if (inst_ty.isError() and !dest_ty.isError()) {
20610 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{});
20611 } else {
20612 try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{});
20613 }
20614 }
20615
20616 // TODO maybe add "cannot store an error in type '{}'" note
20617
20618 break :msg msg;
20619 };
20620 return sema.failWithOwnedErrorMsg(block, msg);
2050020621}
2050120622
20502const InMemoryCoercionResult = enum {
20623const InMemoryCoercionResult = union(enum) {
2050320624 ok,
20504 no_match,
20625 no_match: Pair,
20626 int_not_coercible: Int,
20627 error_union_payload: PairAndChild,
20628 array_len: IntPair,
20629 array_sentinel: Sentinel,
20630 array_elem: PairAndChild,
20631 vector_len: IntPair,
20632 vector_elem: PairAndChild,
20633 optional_shape: Pair,
20634 optional_child: PairAndChild,
20635 from_anyerror,
20636 missing_error: []const []const u8,
20637 /// true if wanted is var args
20638 fn_var_args: bool,
20639 /// true if wanted is generic
20640 fn_generic: bool,
20641 fn_param_count: IntPair,
20642 fn_param_noalias: IntPair,
20643 fn_param_comptime: ComptimeParam,
20644 fn_param: Param,
20645 fn_cc: CC,
20646 fn_return_type: PairAndChild,
20647 ptr_child: PairAndChild,
20648 ptr_addrspace: AddressSpace,
20649 ptr_sentinel: Sentinel,
20650 ptr_size: Size,
20651 ptr_qualifiers: Qualifiers,
20652 ptr_allowzero: Pair,
20653 ptr_bit_range: BitRange,
20654 ptr_alignment: IntPair,
20655
20656 const Pair = struct {
20657 actual: Type,
20658 wanted: Type,
20659 };
20660
20661 const PairAndChild = struct {
20662 child: *InMemoryCoercionResult,
20663 actual: Type,
20664 wanted: Type,
20665 };
20666
20667 const Param = struct {
20668 child: *InMemoryCoercionResult,
20669 actual: Type,
20670 wanted: Type,
20671 index: u64,
20672 };
20673
20674 const ComptimeParam = struct {
20675 index: u64,
20676 wanted: bool,
20677 };
20678
20679 const Sentinel = struct {
20680 // unreachable_value indicates no sentinel
20681 actual: Value,
20682 wanted: Value,
20683 ty: Type,
20684 };
20685
20686 const Int = struct {
20687 actual_signedness: std.builtin.Signedness,
20688 wanted_signedness: std.builtin.Signedness,
20689 actual_bits: u16,
20690 wanted_bits: u16,
20691 };
20692
20693 const IntPair = struct {
20694 actual: u64,
20695 wanted: u64,
20696 };
20697
20698 const Size = struct {
20699 actual: std.builtin.Type.Pointer.Size,
20700 wanted: std.builtin.Type.Pointer.Size,
20701 };
20702
20703 const Qualifiers = struct {
20704 actual_const: bool,
20705 wanted_const: bool,
20706 actual_volatile: bool,
20707 wanted_volatile: bool,
20708 };
20709
20710 const AddressSpace = struct {
20711 actual: std.builtin.AddressSpace,
20712 wanted: std.builtin.AddressSpace,
20713 };
20714
20715 const CC = struct {
20716 actual: std.builtin.CallingConvention,
20717 wanted: std.builtin.CallingConvention,
20718 };
20719
20720 const BitRange = struct {
20721 actual_host: u16,
20722 wanted_host: u16,
20723 actual_offset: u16,
20724 wanted_offset: u16,
20725 };
20726
20727 fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult {
20728 const res = try arena.create(InMemoryCoercionResult);
20729 res.* = child.*;
20730 return res;
20731 }
20732
20733 fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void {
20734 var cur = res;
20735 while (true) switch (cur.*) {
20736 .ok => unreachable,
20737 .no_match => |types| {
20738 try sema.addDeclaredHereNote(msg, types.wanted);
20739 try sema.addDeclaredHereNote(msg, types.actual);
20740 break;
20741 },
20742 .int_not_coercible => |int| {
20743 try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{
20744 @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits,
20745 });
20746 break;
20747 },
20748 .error_union_payload => |pair| {
20749 try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
20750 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20751 });
20752 cur = pair.child;
20753 },
20754 .array_len => |lens| {
20755 try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{
20756 lens.actual, lens.wanted,
20757 });
20758 break;
20759 },
20760 .array_sentinel => |sentinel| {
20761 if (sentinel.actual.tag() != .unreachable_value) {
20762 try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
20763 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20764 });
20765 } else {
20766 try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
20767 sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20768 });
20769 }
20770 break;
20771 },
20772 .array_elem => |pair| {
20773 try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
20774 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20775 });
20776 cur = pair.child;
20777 },
20778 .vector_len => |lens| {
20779 try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{
20780 lens.actual, lens.wanted,
20781 });
20782 break;
20783 },
20784 .vector_elem => |pair| {
20785 try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
20786 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20787 });
20788 cur = pair.child;
20789 },
20790 .optional_shape => |pair| {
20791 var buf_actual: Type.Payload.ElemType = undefined;
20792 var buf_wanted: Type.Payload.ElemType = undefined;
20793 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
20794 pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
20795 });
20796 break;
20797 },
20798 .optional_child => |pair| {
20799 try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
20800 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20801 });
20802 cur = pair.child;
20803 },
20804 .from_anyerror => {
20805 try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{});
20806 break;
20807 },
20808 .missing_error => |missing_errors| {
20809 for (missing_errors) |err| {
20810 try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err});
20811 }
20812 break;
20813 },
20814 .fn_var_args => |wanted_var_args| {
20815 if (wanted_var_args) {
20816 try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{});
20817 } else {
20818 try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{});
20819 }
20820 break;
20821 },
20822 .fn_generic => |wanted_generic| {
20823 if (wanted_generic) {
20824 try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{});
20825 } else {
20826 try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{});
20827 }
20828 break;
20829 },
20830 .fn_param_count => |lens| {
20831 try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{
20832 lens.actual, lens.wanted,
20833 });
20834 break;
20835 },
20836 .fn_param_noalias => |param| {
20837 var index: u6 = 0;
20838 var actual_noalias = false;
20839 while (true) : (index += 1) {
20840 if (param.actual << index != param.wanted << index) {
20841 actual_noalias = (param.actual << index) == (1 << 31);
20842 }
20843 }
20844 if (!actual_noalias) {
20845 try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index});
20846 } else {
20847 try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index});
20848 }
20849 break;
20850 },
20851 .fn_param_comptime => |param| {
20852 if (param.wanted) {
20853 try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index});
20854 } else {
20855 try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index});
20856 }
20857 break;
20858 },
20859 .fn_param => |param| {
20860 try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
20861 param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod),
20862 });
20863 cur = param.child;
20864 },
20865 .fn_cc => |cc| {
20866 try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) });
20867 break;
20868 },
20869 .fn_return_type => |pair| {
20870 try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{
20871 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20872 });
20873 cur = pair.child;
20874 },
20875 .ptr_child => |pair| {
20876 try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
20877 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20878 });
20879 cur = pair.child;
20880 },
20881 .ptr_addrspace => |@"addrspace"| {
20882 try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) });
20883 break;
20884 },
20885 .ptr_sentinel => |sentinel| {
20886 if (sentinel.actual.tag() != .unreachable_value) {
20887 try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
20888 sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20889 });
20890 } else {
20891 try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
20892 sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
20893 });
20894 }
20895 break;
20896 },
20897 .ptr_size => |size| {
20898 try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) });
20899 break;
20900 },
20901 .ptr_qualifiers => |qualifiers| {
20902 const ok_const = !qualifiers.actual_const or qualifiers.wanted_const;
20903 const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile;
20904 if (!ok_const) {
20905 try sema.errNote(block, src, msg, "cast discards const qualifier", .{});
20906 } else if (!ok_volatile) {
20907 try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{});
20908 }
20909 break;
20910 },
20911 .ptr_allowzero => |pair| {
20912 const wanted_allow_zero = pair.wanted.ptrAllowsZero();
20913 const actual_allow_zero = pair.actual.ptrAllowsZero();
20914 if (actual_allow_zero and !wanted_allow_zero) {
20915 try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{
20916 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20917 });
20918 } else {
20919 try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{
20920 pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
20921 });
20922 }
20923 break;
20924 },
20925 .ptr_bit_range => |bit_range| {
20926 if (bit_range.actual_host != bit_range.wanted_host) {
20927 try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{
20928 bit_range.actual_host, bit_range.wanted_host,
20929 });
20930 }
20931 if (bit_range.actual_offset != bit_range.wanted_offset) {
20932 try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{
20933 bit_range.actual_offset, bit_range.wanted_offset,
20934 });
20935 }
20936 break;
20937 },
20938 .ptr_alignment => |pair| {
20939 try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{
20940 pair.actual, pair.wanted,
20941 });
20942 break;
20943 },
20944 };
20945 }
2050520946};
2050620947
20948fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 {
20949 return switch (size) {
20950 .One => "single",
20951 .Many => "many",
20952 .C => "C",
20953 .Slice => unreachable,
20954 };
20955}
20956
2050720957/// If pointers have the same representation in runtime memory, a bitcast AIR instruction
2050820958/// may be used for the coercion.
2050920959/// * `const` attribute can be gained
......@@ -20513,8 +20963,6 @@ const InMemoryCoercionResult = enum {
2051320963/// * bit offset attributes must match exactly
2051420964/// * `*`/`[*]` must match exactly, but `[*c]` matches either one
2051520965/// * sentinel-terminated pointers can coerce into `[*]`
20516/// TODO improve this function to report recursive compile errors like it does in stage1.
20517/// look at the function types_match_const_cast_only
2051820966fn coerceInMemoryAllowed(
2051920967 sema: *Sema,
2052020968 block: *Block,
......@@ -20532,11 +20980,25 @@ fn coerceInMemoryAllowed(
2053220980 if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {
2053320981 const dest_info = dest_ty.intInfo(target);
2053420982 const src_info = src_ty.intInfo(target);
20983
2053520984 if (dest_info.signedness == src_info.signedness and
2053620985 dest_info.bits == src_info.bits)
2053720986 {
2053820987 return .ok;
2053920988 }
20989
20990 if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or
20991 // small enough unsigned ints can get casted to large enough signed ints
20992 (dest_info.signedness == .signed and (src_info.signedness == .unsigned or dest_info.bits <= src_info.bits)) or
20993 (dest_info.signedness == .unsigned and src_info.signedness == .signed))
20994 {
20995 return InMemoryCoercionResult{ .int_not_coercible = .{
20996 .actual_signedness = src_info.signedness,
20997 .wanted_signedness = dest_info.signedness,
20998 .actual_bits = src_info.bits,
20999 .wanted_bits = dest_info.bits,
21000 } };
21001 }
2054021002 }
2054121003
2054221004 // Differently-named floats with the same number of bits.
......@@ -20574,9 +21036,15 @@ fn coerceInMemoryAllowed(
2057421036
2057521037 // Error Unions
2057621038 if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
20577 const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src);
20578 if (child == .no_match) {
20579 return child;
21039 const dest_payload = dest_ty.errorUnionPayload();
21040 const src_payload = src_ty.errorUnionPayload();
21041 const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src);
21042 if (child != .ok) {
21043 return InMemoryCoercionResult{ .error_union_payload = .{
21044 .child = try child.dupe(sema.arena),
21045 .actual = src_payload,
21046 .wanted = dest_payload,
21047 } };
2058021048 }
2058121049 return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);
2058221050 }
......@@ -20587,57 +21055,89 @@ fn coerceInMemoryAllowed(
2058721055 }
2058821056
2058921057 // Arrays
20590 if (dest_tag == .Array and src_tag == .Array) arrays: {
21058 if (dest_tag == .Array and src_tag == .Array) {
2059121059 const dest_info = dest_ty.arrayInfo();
2059221060 const src_info = src_ty.arrayInfo();
20593 if (dest_info.len != src_info.len) break :arrays;
21061 if (dest_info.len != src_info.len) {
21062 return InMemoryCoercionResult{ .array_len = .{
21063 .actual = src_info.len,
21064 .wanted = dest_info.len,
21065 } };
21066 }
2059421067
2059521068 const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src);
20596 if (child == .no_match) {
20597 return child;
21069 if (child != .ok) {
21070 return InMemoryCoercionResult{ .array_elem = .{
21071 .child = try child.dupe(sema.arena),
21072 .actual = src_info.elem_type,
21073 .wanted = dest_info.elem_type,
21074 } };
2059821075 }
2059921076 const ok_sent = dest_info.sentinel == null or
2060021077 (src_info.sentinel != null and
2060121078 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod));
2060221079 if (!ok_sent) {
20603 return .no_match;
21080 return InMemoryCoercionResult{ .array_sentinel = .{
21081 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
21082 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
21083 .ty = dest_info.elem_type,
21084 } };
2060421085 }
2060521086 return .ok;
2060621087 }
2060721088
2060821089 // Vectors
20609 if (dest_tag == .Vector and src_tag == .Vector) vectors: {
21090 if (dest_tag == .Vector and src_tag == .Vector) {
2061021091 const dest_len = dest_ty.vectorLen();
2061121092 const src_len = src_ty.vectorLen();
20612 if (dest_len != src_len) break :vectors;
21093 if (dest_len != src_len) {
21094 return InMemoryCoercionResult{ .vector_len = .{
21095 .actual = src_len,
21096 .wanted = dest_len,
21097 } };
21098 }
2061321099
2061421100 const dest_elem_ty = dest_ty.scalarType();
2061521101 const src_elem_ty = src_ty.scalarType();
2061621102 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
20617 if (child == .no_match) break :vectors;
21103 if (child != .ok) {
21104 return InMemoryCoercionResult{ .vector_elem = .{
21105 .child = try child.dupe(sema.arena),
21106 .actual = src_elem_ty,
21107 .wanted = dest_elem_ty,
21108 } };
21109 }
2061821110
2061921111 return .ok;
2062021112 }
2062121113
2062221114 // Optionals
20623 if (dest_tag == .Optional and src_tag == .Optional) optionals: {
21115 if (dest_tag == .Optional and src_tag == .Optional) {
2062421116 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {
20625 // TODO "optional type child '{}' cannot cast into optional type '{}'"
20626 return .no_match;
21117 return InMemoryCoercionResult{ .optional_shape = .{
21118 .actual = src_ty,
21119 .wanted = dest_ty,
21120 } };
2062721121 }
2062821122 const dest_child_type = dest_ty.optionalChild(&dest_buf);
2062921123 const src_child_type = src_ty.optionalChild(&src_buf);
2063021124
2063121125 const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);
20632 if (child == .no_match) {
20633 // TODO "optional type child '{}' cannot cast into optional type child '{}'"
20634 break :optionals;
21126 if (child != .ok) {
21127 return InMemoryCoercionResult{ .optional_child = .{
21128 .child = try child.dupe(sema.arena),
21129 .actual = src_child_type,
21130 .wanted = dest_child_type,
21131 } };
2063521132 }
2063621133
2063721134 return .ok;
2063821135 }
2063921136
20640 return .no_match;
21137 return InMemoryCoercionResult{ .no_match = .{
21138 .actual = dest_ty,
21139 .wanted = src_ty,
21140 } };
2064121141}
2064221142
2064321143fn coerceInMemoryAllowedErrorSets(
......@@ -20704,6 +21204,9 @@ fn coerceInMemoryAllowedErrorSets(
2070421204 }
2070521205 }
2070621206
21207 var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa);
21208 defer missing_error_buf.deinit();
21209
2070721210 switch (src_ty.tag()) {
2070821211 .error_set_inferred => {
2070921212 const src_data = src_ty.castTag(.error_set_inferred).?.data;
......@@ -20712,15 +21215,21 @@ fn coerceInMemoryAllowedErrorSets(
2071221215 // src anyerror status might have changed after the resolution.
2071321216 if (src_ty.isAnyError()) {
2071421217 // dest_ty.isAnyError() == true is already checked for at this point.
20715 return .no_match;
21218 return .from_anyerror;
2071621219 }
2071721220
2071821221 for (src_data.errors.keys()) |key| {
2071921222 if (!dest_ty.errorSetHasField(key)) {
20720 return .no_match;
21223 try missing_error_buf.append(key);
2072121224 }
2072221225 }
2072321226
21227 if (missing_error_buf.items.len != 0) {
21228 return InMemoryCoercionResult{
21229 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
21230 };
21231 }
21232
2072421233 return .ok;
2072521234 },
2072621235 .error_set_single => {
......@@ -20728,37 +21237,52 @@ fn coerceInMemoryAllowedErrorSets(
2072821237 if (dest_ty.errorSetHasField(name)) {
2072921238 return .ok;
2073021239 }
21240 const list = try sema.arena.alloc([]const u8, 1);
21241 list[0] = name;
21242 return InMemoryCoercionResult{ .missing_error = list };
2073121243 },
2073221244 .error_set_merged => {
2073321245 const names = src_ty.castTag(.error_set_merged).?.data.keys();
2073421246 for (names) |name| {
2073521247 if (!dest_ty.errorSetHasField(name)) {
20736 return .no_match;
21248 try missing_error_buf.append(name);
2073721249 }
2073821250 }
2073921251
21252 if (missing_error_buf.items.len != 0) {
21253 return InMemoryCoercionResult{
21254 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
21255 };
21256 }
21257
2074021258 return .ok;
2074121259 },
2074221260 .error_set => {
2074321261 const names = src_ty.castTag(.error_set).?.data.names.keys();
2074421262 for (names) |name| {
2074521263 if (!dest_ty.errorSetHasField(name)) {
20746 return .no_match;
21264 try missing_error_buf.append(name);
2074721265 }
2074821266 }
2074921267
21268 if (missing_error_buf.items.len != 0) {
21269 return InMemoryCoercionResult{
21270 .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
21271 };
21272 }
21273
2075021274 return .ok;
2075121275 },
2075221276 .anyerror => switch (dest_ty.tag()) {
20753 .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above.
20754 .error_set_single, .error_set_merged, .error_set => {},
21277 .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above.
21278 .error_set_single, .error_set_merged, .error_set => return .from_anyerror,
2075521279 .anyerror => unreachable, // Filtered out above.
2075621280 else => unreachable,
2075721281 },
2075821282 else => unreachable,
2075921283 }
2076021284
20761 return .no_match;
21285 unreachable;
2076221286}
2076321287
2076421288fn coerceInMemoryAllowedFns(
......@@ -20774,44 +21298,67 @@ fn coerceInMemoryAllowedFns(
2077421298 const src_info = src_ty.fnInfo();
2077521299
2077621300 if (dest_info.is_var_args != src_info.is_var_args) {
20777 return .no_match;
21301 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
2077821302 }
2077921303
2078021304 if (dest_info.is_generic != src_info.is_generic) {
20781 return .no_match;
21305 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
21306 }
21307
21308 if (dest_info.cc != src_info.cc) {
21309 return InMemoryCoercionResult{ .fn_cc = .{
21310 .actual = src_info.cc,
21311 .wanted = dest_info.cc,
21312 } };
2078221313 }
2078321314
2078421315 if (!src_info.return_type.isNoReturn()) {
2078521316 const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);
20786 if (rt == .no_match) {
20787 return rt;
21317 if (rt != .ok) {
21318 return InMemoryCoercionResult{ .fn_return_type = .{
21319 .child = try rt.dupe(sema.arena),
21320 .actual = src_info.return_type,
21321 .wanted = dest_info.return_type,
21322 } };
2078821323 }
2078921324 }
2079021325
2079121326 if (dest_info.param_types.len != src_info.param_types.len) {
20792 return .no_match;
21327 return InMemoryCoercionResult{ .fn_param_count = .{
21328 .actual = dest_info.param_types.len,
21329 .wanted = dest_info.param_types.len,
21330 } };
21331 }
21332
21333 if (dest_info.noalias_bits != src_info.noalias_bits) {
21334 return InMemoryCoercionResult{ .fn_param_noalias = .{
21335 .actual = dest_info.noalias_bits,
21336 .wanted = dest_info.noalias_bits,
21337 } };
2079321338 }
2079421339
2079521340 for (dest_info.param_types) |dest_param_ty, i| {
2079621341 const src_param_ty = src_info.param_types[i];
2079721342
2079821343 if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
20799 return .no_match;
21344 return InMemoryCoercionResult{ .fn_param_comptime = .{
21345 .index = i,
21346 .wanted = dest_info.comptime_params[i],
21347 } };
2080021348 }
2080121349
20802 // TODO: noalias
20803
2080421350 // Note: Cast direction is reversed here.
2080521351 const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
20806 if (param == .no_match) {
20807 return param;
21352 if (param != .ok) {
21353 return InMemoryCoercionResult{ .fn_param = .{
21354 .child = try param.dupe(sema.arena),
21355 .actual = src_param_ty,
21356 .wanted = dest_param_ty,
21357 .index = i,
21358 } };
2080821359 }
2080921360 }
2081021361
20811 if (dest_info.cc != src_info.cc) {
20812 return .no_match;
20813 }
20814
2081521362 return .ok;
2081621363}
2081721364
......@@ -20830,26 +21377,13 @@ fn coerceInMemoryAllowedPtrs(
2083021377 const dest_info = dest_ptr_ty.ptrInfo().data;
2083121378 const src_info = src_ptr_ty.ptrInfo().data;
2083221379
20833 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
20834 if (child == .no_match) {
20835 return child;
20836 }
20837
20838 if (dest_info.@"addrspace" != src_info.@"addrspace") {
20839 return .no_match;
20840 }
20841
20842 const ok_sent = dest_info.sentinel == null or src_info.size == .C or
20843 (src_info.sentinel != null and
20844 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
20845 if (!ok_sent) {
20846 return .no_match;
20847 }
20848
2084921380 const ok_ptr_size = src_info.size == dest_info.size or
2085021381 src_info.size == .C or dest_info.size == .C;
2085121382 if (!ok_ptr_size) {
20852 return .no_match;
21383 return InMemoryCoercionResult{ .ptr_size = .{
21384 .actual = src_info.size,
21385 .wanted = dest_info.size,
21386 } };
2085321387 }
2085421388
2085521389 const ok_cv_qualifiers =
......@@ -20857,7 +21391,28 @@ fn coerceInMemoryAllowedPtrs(
2085721391 (!src_info.@"volatile" or dest_info.@"volatile");
2085821392
2085921393 if (!ok_cv_qualifiers) {
20860 return .no_match;
21394 return InMemoryCoercionResult{ .ptr_qualifiers = .{
21395 .actual_const = !src_info.mutable,
21396 .wanted_const = !dest_info.mutable,
21397 .actual_volatile = src_info.@"volatile",
21398 .wanted_volatile = dest_info.@"volatile",
21399 } };
21400 }
21401
21402 if (dest_info.@"addrspace" != src_info.@"addrspace") {
21403 return InMemoryCoercionResult{ .ptr_addrspace = .{
21404 .actual = src_info.@"addrspace",
21405 .wanted = dest_info.@"addrspace",
21406 } };
21407 }
21408
21409 const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src);
21410 if (child != .ok) {
21411 return InMemoryCoercionResult{ .ptr_child = .{
21412 .child = try child.dupe(sema.arena),
21413 .actual = src_info.pointee_type,
21414 .wanted = dest_info.pointee_type,
21415 } };
2086121416 }
2086221417
2086321418 const dest_allow_zero = dest_ty.ptrAllowsZero();
......@@ -20867,13 +21422,32 @@ fn coerceInMemoryAllowedPtrs(
2086721422 (src_allow_zero or !dest_is_mut)) or
2086821423 (!dest_allow_zero and !src_allow_zero);
2086921424 if (!ok_allows_zero) {
20870 return .no_match;
21425 return InMemoryCoercionResult{ .ptr_allowzero = .{
21426 .actual = src_ty,
21427 .wanted = dest_ty,
21428 } };
2087121429 }
2087221430
2087321431 if (src_info.host_size != dest_info.host_size or
2087421432 src_info.bit_offset != dest_info.bit_offset)
2087521433 {
20876 return .no_match;
21434 return InMemoryCoercionResult{ .ptr_bit_range = .{
21435 .actual_host = src_info.host_size,
21436 .wanted_host = dest_info.host_size,
21437 .actual_offset = src_info.bit_offset,
21438 .wanted_offset = dest_info.bit_offset,
21439 } };
21440 }
21441
21442 const ok_sent = dest_info.sentinel == null or src_info.size == .C or
21443 (src_info.sentinel != null and
21444 dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
21445 if (!ok_sent) {
21446 return InMemoryCoercionResult{ .ptr_sentinel = .{
21447 .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
21448 .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
21449 .ty = dest_info.pointee_type,
21450 } };
2087721451 }
2087821452
2087921453 // If both pointers have alignment 0, it means they both want ABI alignment.
......@@ -20898,7 +21472,10 @@ fn coerceInMemoryAllowedPtrs(
2089821472 dest_info.pointee_type.abiAlignment(target);
2089921473
2090021474 if (dest_align > src_align) {
20901 return .no_match;
21475 return InMemoryCoercionResult{ .ptr_alignment = .{
21476 .actual = src_align,
21477 .wanted = dest_align,
21478 } };
2090221479 }
2090321480
2090421481 break :alignment;
......@@ -20974,6 +21551,8 @@ fn storePtr2(
2097421551 // TODO do the same thing for anon structs as for tuples above.
2097521552 // However, beware of the need to handle missing/extra fields.
2097621553
21554 const is_ret = air_tag == .ret_ptr;
21555
2097721556 // Detect if we are storing an array operand to a bitcasted vector pointer.
2097821557 // If so, we instead reach through the bitcasted pointer to the vector pointer,
2097921558 // bitcast the array operand to a vector, and then lower this as a store of
......@@ -20982,12 +21561,18 @@ fn storePtr2(
2098221561 // https://github.com/ziglang/zig/issues/11154
2098321562 if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
2098421563 const vector_ty = sema.typeOf(vector_ptr).childType();
20985 const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src);
21564 const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) {
21565 error.NotCoercible => unreachable,
21566 else => |e| return e,
21567 };
2098621568 try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store);
2098721569 return;
2098821570 }
2098921571
20990 const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
21572 const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, true, is_ret) catch |err| switch (err) {
21573 error.NotCoercible => unreachable,
21574 else => |e| return e,
21575 };
2099121576 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
2099221577
2099321578 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
......@@ -21017,7 +21602,11 @@ fn storePtr2(
2101721602
2101821603 try sema.requireRuntimeBlock(block, runtime_src);
2101921604 try sema.queueFullTypeResolution(elem_ty);
21020 _ = try block.addBinOp(air_tag, ptr, operand);
21605 if (is_ret) {
21606 _ = try block.addBinOp(.store, ptr, operand);
21607 } else {
21608 _ = try block.addBinOp(air_tag, ptr, operand);
21609 }
2102121610}
2102221611
2102321612/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
test/cases/aarch64-macos/hello_world_with_updates.1.zig+2-1
......@@ -2,4 +2,5 @@ pub export fn main() noreturn {}
22
33// error
44//
5// :1:32: error: expected type 'noreturn', found 'void'
5// :1:32: error: function declared 'noreturn' returns
6// :1:22: note: 'noreturn' declared here
test/cases/compile_errors/address_of_number_literal.zig+2
......@@ -8,3 +8,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); }
88// target=native
99//
1010// :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'
12// :3:10: note: function return type declared here
test/cases/compile_errors/any_typed_null_to_any_typed_optional.zig+5-5
......@@ -1,11 +1,11 @@
1pub fn main() void {
1pub export fn entry() void {
22 var a: ?*anyopaque = undefined;
33 a = @as(?usize, null);
44}
55
66// error
7// output_mode=Exe
8// backend=stage2,llvm
9// target=x86_64-linux,x86_64-macos
7// backend=stage2
8// target=native
109//
11// :3:21: error: expected type '*anyopaque', found '?usize'
10// :3:21: error: expected type '?*anyopaque', found '?usize'
11// :3:21: note: optional type child 'usize' cannot cast into optional type child '*anyopaque'
test/cases/compile_errors/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig created+23
......@@ -0,0 +1,23 @@
1fn maybe(is: bool) ?u8 {
2 if (is) return @as(u8, 10) else return null;
3}
4const U = union {
5 Ye: u8,
6};
7const S = struct {
8 num: u8,
9};
10export fn entry() void {
11 var u = U{ .Ye = maybe(false) };
12 var s = S{ .num = maybe(false) };
13 _ = u;
14 _ = s;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :11:27: error: expected type 'u8', found '?u8'
22// :11:27: note: cannot convert optional to payload type
23// :11:27: note: consider using `.?`, `orelse`, or `if`
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_between_optional_T_where_T_is_not_a_pointer.zig created+26
......@@ -0,0 +1,26 @@
1pub const fnty1 = ?*const fn (i8) void;
2pub const fnty2 = ?*const fn (u64) void;
3export fn entry1() void {
4 var a: fnty1 = undefined;
5 var b: fnty2 = undefined;
6 a = b;
7}
8
9pub const fnty3 = ?*const fn (u63) void;
10export fn entry2() void {
11 var a: fnty3 = undefined;
12 var b: fnty2 = undefined;
13 a = b;
14}
15
16// error
17// backend=stage2
18// target=native
19//
20// :6:9: error: expected type '?*const fn(i8) void', found '?*const fn(u64) void'
21// :6:9: note: pointer type child 'fn(u64) void' cannot cast into pointer type child 'fn(i8) void'
22// :6:9: note: parameter 0 'u64' cannot cast into 'i8'
23// :6:9: note: unsigned 64-bit int cannot represent all possible signed 8-bit values
24// :13:9: error: expected type '?*const fn(u63) void', found '?*const fn(u64) void'
25// :13:9: note: pointer type child 'fn(u64) void' cannot cast into pointer type child 'fn(u63) void'
26// :13:9: note: parameter 0 'u64' cannot cast into 'u63'
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)); }
1919// target=native
2020//
2121// :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/discarding_error_value.zig+2-1
......@@ -9,4 +9,5 @@ fn foo() !void {
99// backend=stage2
1010// target=native
1111//
12// :2:12: error: error is discarded. consider using `try`, `catch`, or `if`
12// :2:12: error: error is discarded
13// :2:12: note: consider using `try`, `catch`, or `if`
test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig+1
......@@ -11,3 +11,4 @@ export fn entry() void {
1111// target=native
1212//
1313// :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/ignored_deferred_function_call.zig+2-1
......@@ -7,4 +7,5 @@ fn bar() anyerror!i32 { return 0; }
77// backend=stage2
88// target=native
99//
10// :2:14: error: error is ignored. consider using `try`, `catch`, or `if`
10// :2:14: error: error is ignored
11// :2:14: note: consider using `try`, `catch`, or `if`
test/cases/compile_errors/ignored_expression_in_while_continuation.zig+6-3
......@@ -17,6 +17,9 @@ fn bad() anyerror!void {
1717// backend=stage2
1818// target=native
1919//
20// :2:24: error: error is ignored. consider using `try`, `catch`, or `if`
21// :6:25: error: error is ignored. consider using `try`, `catch`, or `if`
22// :10:25: error: error is ignored. consider using `try`, `catch`, or `if`
20// :2:24: error: error is ignored
21// :2:24: note: consider using `try`, `catch`, or `if`
22// :6:25: error: error is ignored
23// :6:25: note: consider using `try`, `catch`, or `if`
24// :10:25: error: error is ignored
25// :10:25: note: consider using `try`, `catch`, or `if`
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_cast_to_c_ptr_from_int.zig created+15
......@@ -0,0 +1,15 @@
1const std = @import("std");
2export fn entry1() void {
3 _ = @as([*c]u8, @as(u65, std.math.maxInt(u65)));
4}
5export fn entry2() void {
6 _ = @as([*c]u8, std.math.maxInt(u65));
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :3:21: error: expected type '[*c]u8', found 'u65'
14// :3:21: note: unsigned 64-bit int cannot represent all possible unsigned 65-bit values
15// :6:36: error: expected type '[*c]u8', found 'comptime_int'
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 {
1515// target=native
1616//
1717// :9:22: error: expected type 'u2', found 'tmp.Small'
18// :1:15: note: enum declared here
test/cases/compile_errors/incompatible_sentinels.zig created+31
......@@ -0,0 +1,31 @@
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// :3:35: note: function return type declared here
25// :7:12: error: expected type '[*:0]u8', found '[*]u8'
26// :7:12: note: destination pointer requires '0' sentinel
27// :6:31: note: function return type declared here
28// :10:35: error: expected type '[2:0]u8', found '[2:255]u8'
29// :10:35: note: array sentinel '255' cannot cast into array sentinel '0'
30// :14:31: error: expected type '[2:0]u8', found '[2]u8'
31// :14:31: note: destination array requires '0' sentinel
test/cases/compile_errors/incorrect_return_type.zig+3
......@@ -19,3 +19,6 @@
1919// target=native
2020//
2121// :8:16: error: expected type 'tmp.A', found 'tmp.B'
22// :10:12: note: struct declared here
23// :4:12: note: struct declared here
24// :7:11: note: function return type declared here
test/cases/compile_errors/invalid_address_space_coercion.zig+2
......@@ -11,3 +11,5 @@ pub fn main() void {
1111// target=x86_64-linux,x86_64-macos
1212//
1313// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:12: note: address space 'gs' cannot cast into address space 'generic'
15// :1:34: note: function return type declared here
test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig+1
......@@ -15,3 +15,4 @@ fn foo(x: usize) void {
1515// target=native
1616//
1717// :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+2
......@@ -11,3 +11,5 @@ pub fn main() void {
1111// target=x86_64-linux,x86_64-macos
1212//
1313// :2:12: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:12: note: address space 'gs' cannot cast into address space 'generic'
15// :1:34: note: function return type declared here
test/cases/compile_errors/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig created+14
......@@ -0,0 +1,14 @@
1export fn foo() void {
2 var u: ?*anyopaque = null;
3 var v: *anyopaque = undefined;
4 v = u;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :4:9: error: expected type '*anyopaque', found '?*anyopaque'
12// :4:9: note: cannot convert optional to payload type
13// :4:9: note: consider using `.?`, `orelse`, or `if`
14// :4:9: note: '?*anyopaque' could have null values which are illegal in type '*anyopaque'
test/cases/compile_errors/not_an_enum_type.zig+1
......@@ -17,3 +17,4 @@ const ExpectedVarDeclOrFn = struct {};
1717// target=native
1818//
1919// :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 {
1010// target=native
1111//
1212// :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+2
......@@ -11,3 +11,5 @@ export fn entry2() void {
1111// target=x86_64-linux,x86_64-macos
1212//
1313// :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'
15// :1:34: note: function return type declared here
test/cases/compile_errors/pointers_with_different_address_spaces.zig+2
......@@ -11,3 +11,5 @@ pub fn main() void {
1111// target=x86_64-linux,x86_64-macos
1212//
1313// :2:13: error: expected type '*i32', found '*addrspace(.gs) i32'
14// :2:13: note: address space 'gs' cannot cast into address space 'generic'
15// :1:35: note: function return type declared here
test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig created+23
......@@ -0,0 +1,23 @@
1const Foo = struct {
2 ptr: ?*usize,
3 uval: u32,
4};
5fn get_uval(x: u32) !u32 {
6 _ = x;
7 return error.NotFound;
8}
9export fn entry() void {
10 const afoo = Foo{
11 .ptr = null,
12 .uval = get_uval(42),
13 };
14 _ = afoo;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :12:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
22// :12:25: note: cannot convert error union to payload type
23// :12:25: note: consider using `try`, `catch`, or `if`
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr.zig created+20
......@@ -0,0 +1,20 @@
1export fn entry() void {
2 var damn = Container{
3 .not_optional = getOptional(),
4 };
5 _ = damn;
6}
7pub fn getOptional() ?i32 {
8 return 0;
9}
10pub const Container = struct {
11 not_optional: i32,
12};
13
14// error
15// backend=stage2
16// target=native
17//
18// :3:36: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type
20// :3:36: note: consider using `.?`, `orelse`, or `if`
test/cases/compile_errors/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig created+20
......@@ -0,0 +1,20 @@
1export fn entry() void {
2 var damn = Container{
3 .not_optional = getOptional(i32),
4 };
5 _ = damn;
6}
7pub fn getOptional(comptime T: type) ?T {
8 return 0;
9}
10pub const Container = struct {
11 not_optional: i32,
12};
13
14// error
15// backend=stage2
16// target=native
17//
18// :3:36: error: expected type 'i32', found '?i32'
19// :3:36: note: cannot convert optional to payload type
20// :3:36: note: consider using `.?`, `orelse`, or `if`
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 {
77// target=native
88//
99// :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+13
......@@ -0,0 +1,13 @@
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
13// :1:10: note: function return type declared here
test/cases/compile_errors/stage1/obj/assigning_to_struct_or_union_fields_that_are_not_optionals_with_a_function_that_returns_an_optional.zig deleted-21
......@@ -1,21 +0,0 @@
1fn maybe(is: bool) ?u8 {
2 if (is) return @as(u8, 10) else return null;
3}
4const U = union {
5 Ye: u8,
6};
7const S = struct {
8 num: u8,
9};
10export fn entry() void {
11 var u = U{ .Ye = maybe(false) };
12 var s = S{ .num = maybe(false) };
13 _ = u;
14 _ = s;
15}
16
17// error
18// backend=stage1
19// target=native
20//
21// tmp.zig:11:27: error: cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type 'u8', found '?u8'
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/issue_5618_coercion_of_optional_anyopaque_to_anyopaque_must_fail.zig deleted-11
......@@ -1,11 +0,0 @@
1export fn foo() void {
2 var u: ?*anyopaque = null;
3 var v: *anyopaque = undefined;
4 v = u;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:4:9: error: cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type '*anyopaque', found '?*anyopaque'
test/cases/compile_errors/stage1/obj/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig deleted-21
......@@ -1,21 +0,0 @@
1const Foo = struct {
2 ptr: ?*usize,
3 uval: u32,
4};
5fn get_uval(x: u32) !u32 {
6 _ = x;
7 return error.NotFound;
8}
9export fn entry() void {
10 const afoo = Foo{
11 .ptr = null,
12 .uval = get_uval(42),
13 };
14 _ = afoo;
15}
16
17// error
18// backend=stage1
19// target=native
20//
21// tmp.zig:12:25: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'
test/cases/compile_errors/stage1/obj/result_location_incompatibility_mismatching_handle_is_ptr.zig deleted-18
......@@ -1,18 +0,0 @@
1export fn entry() void {
2 var damn = Container{
3 .not_optional = getOptional(),
4 };
5 _ = damn;
6}
7pub fn getOptional() ?i32 {
8 return 0;
9}
10pub const Container = struct {
11 not_optional: i32,
12};
13
14// error
15// backend=stage1
16// target=native
17//
18// tmp.zig:3:36: error: cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type 'i32', found '?i32'
test/cases/compile_errors/stage1/obj/result_location_incompatibility_mismatching_handle_is_ptr_generic_call.zig deleted-18
......@@ -1,18 +0,0 @@
1export fn entry() void {
2 var damn = Container{
3 .not_optional = getOptional(i32),
4 };
5 _ = damn;
6}
7pub fn getOptional(comptime T: type) ?T {
8 return 0;
9}
10pub const Container = struct {
11 not_optional: i32,
12};
13
14// error
15// backend=stage1
16// target=native
17//
18// tmp.zig:3:36: error: cannot convert optional to payload type. consider using `.?`, `orelse`, or `if`. expected type 'i32', found '?i32'
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/stage1/test/cast_between_optional_T_where_T_is_not_a_pointer.zig deleted-15
......@@ -1,15 +0,0 @@
1pub const fnty1 = ?fn (i8) void;
2pub const fnty2 = ?fn (u64) void;
3export fn entry() void {
4 var a: fnty1 = undefined;
5 var b: fnty2 = undefined;
6 a = b;
7}
8
9// error
10// backend=stage1
11// target=native
12// is_test=1
13//
14// tmp.zig:6:9: error: expected type '?fn(i8) void', found '?fn(u64) void'
15// tmp.zig:6:9: note: optional type child 'fn(u64) void' cannot cast into optional type child 'fn(i8) void'
test/cases/compile_errors/stage1/test/helpful_return_type_error_message.zig+12-10
......@@ -16,15 +16,17 @@ export fn quux() u32 {
1616}
1717
1818// error
19// backend=stage1
19// backend=stage2
2020// target=native
21// is_test=1
2221//
23// tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}'
24// tmp.zig:1:17: note: function cannot return an error
25// tmp.zig:8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set'
26// tmp.zig:7:17: note: function cannot return an error
27// tmp.zig:11:15: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
28// tmp.zig:10:17: note: function cannot return an error
29// tmp.zig:15:14: error: cannot convert error union to payload type. consider using `try`, `catch`, or `if`. expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
30// tmp.zig:14:5: note: cannot store an error in type 'u32'
22// :2:18: error: expected type 'u32', found 'error{Ohno}'
23// :1:17: note: function cannot return an error
24// :8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set'
25// :7:17: note: function cannot return an error
26// :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
27// :10:17: note: function cannot return an error
28// :11:15: note: cannot convert error union to payload type
29// :11:15: note: consider using `try`, `catch`, or `if`
30// :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
31// :15:14: note: cannot convert error union to payload type
32// :15:14: note: consider using `try`, `catch`, or `if`
test/cases/compile_errors/try_in_function_with_non_error_return_type.zig+1
......@@ -8,3 +8,4 @@ fn something() anyerror!void { }
88// target=native
99//
1010// :2:5: error: expected type 'void', found 'anyerror'
11// :1:15: note: function cannot return an error
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+3-1
......@@ -10,4 +10,6 @@ export fn main() void {
1010// backend=stage2
1111// target=native
1212//
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/unreachable_with_return.zig+2-1
......@@ -5,4 +5,5 @@ export fn entry() void { a(); }
55// backend=stage2
66// target=native
77//
8// :1:18: error: expected type 'noreturn', found 'void'
8// :1:18: error: function declared 'noreturn' returns
9// :1:8: note: 'noreturn' declared here
test/cases/compile_errors/variable_has_wrong_type.zig+1
......@@ -8,3 +8,4 @@ export fn f() i32 {
88// target=native
99//
1010// :3:12: error: expected type 'i32', found '*const [1:0]u8'
11// :1:15: note: function return type declared here
test/cases/compile_errors/wrong_type_for_reify_type.zig+1
......@@ -7,3 +7,4 @@ export fn entry() void {
77// target=native
88//
99// :2:15: error: expected type 'builtin.Type', found 'comptime_int'
10// :?:?: note: union declared here
test/cases/x86_64-linux/hello_world_with_updates.1.zig+2-1
......@@ -2,4 +2,5 @@ pub export fn _start() noreturn {}
22
33// error
44//
5// :1:34: error: expected type 'noreturn', found 'void'
5// :1:34: error: function declared 'noreturn' returns
6// :1:24: note: 'noreturn' declared here
test/cases/x86_64-macos/hello_world_with_updates.1.zig+2-1
......@@ -2,4 +2,5 @@ pub export fn main() noreturn {}
22
33// error
44//
5// :1:32: error: expected type 'noreturn', found 'void'
5// :1:32: error: function declared 'noreturn' returns
6// :1:22: note: 'noreturn' declared here