From b9f01bc39452042be1609b63f3066cfcac82f273 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 7 Jul 2022 20:54:10 +0300 Subject: [PATCH] Sema: add detailed error notes to `coerceInMemoryAllowed` --- src/Sema.zig | 599 +++++++++++++++--- .../address_of_number_literal.zig | 1 + ...cit_cast_from_const_T_to_array_len_1_T.zig | 6 +- ...et_to_error_union_of_smaller_error_set.zig | 15 + .../cast_global_error_set_to_error_set.zig | 6 +- ..._bit_offset_pointer_to_regular_pointer.zig | 2 + ...licit_cast_double_pointer_to_anyopaque.zig | 1 + ...for_function_parameter_incompatibility.zig | 13 + ...mplicit_cast_of_error_set_not_a_subset.zig | 6 +- ...ers_which_would_mess_up_null_semantics.zig | 26 + .../implicitly_casting_enum_to_tag_type.zig | 1 + .../compile_errors/incompatible_sentinels.zig | 29 + .../compile_errors/incorrect_return_type.zig | 2 + .../invalid_address_space_coercion.zig | 1 + ...nvalid_cast_from_integral_type_to_enum.zig | 1 + ...ace_when_taking_address_of_dereference.zig | 1 + .../cases/compile_errors/not_an_enum_type.zig | 1 + ..._not-aligned-enough_pointer_to_cmpxchg.zig | 1 + .../pointer_with_different_address_spaces.zig | 1 + ...pointers_with_different_address_spaces.zig | 1 + ...fting_RHS_is_log2_of_LHS_int_bit_width.zig | 1 + .../slice_sentinel_mismatch-2.zig | 12 + ...et_to_error_union_of_smaller_error_set.zig | 16 - ...for_function_parameter_incompatibility.zig | 12 - ...ers_which_would_mess_up_null_semantics.zig | 26 - .../stage1/obj/incompatible_sentinels.zig | 29 - .../stage1/obj/slice_sentinel_mismatch-2.zig | 12 - .../obj/type_checking_function_pointers.zig | 13 - .../type_checking_function_pointers.zig | 15 + ...e_mismatch_in_C_prototype_with_varargs.zig | 2 + .../wrong_type_for_reify_type.zig | 1 + 31 files changed, 663 insertions(+), 190 deletions(-) rename test/cases/compile_errors/{stage1/obj => }/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig (55%) create mode 100644 test/cases/compile_errors/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig rename test/cases/compile_errors/{stage1/obj => }/cast_global_error_set_to_error_set.zig (52%) create mode 100644 test/cases/compile_errors/error_note_for_function_parameter_incompatibility.zig rename test/cases/compile_errors/{stage1/obj => }/implicit_cast_of_error_set_not_a_subset.zig (56%) create mode 100644 test/cases/compile_errors/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig create mode 100644 test/cases/compile_errors/incompatible_sentinels.zig create mode 100644 test/cases/compile_errors/slice_sentinel_mismatch-2.zig delete mode 100644 test/cases/compile_errors/stage1/obj/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig delete mode 100644 test/cases/compile_errors/stage1/obj/error_note_for_function_parameter_incompatibility.zig delete mode 100644 test/cases/compile_errors/stage1/obj/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig delete mode 100644 test/cases/compile_errors/stage1/obj/incompatible_sentinels.zig delete mode 100644 test/cases/compile_errors/stage1/obj/slice_sentinel_mismatch-2.zig delete mode 100644 test/cases/compile_errors/stage1/obj/type_checking_function_pointers.zig create mode 100644 test/cases/compile_errors/type_checking_function_pointers.zig diff --git a/src/Sema.zig b/src/Sema.zig index 0e7c1c5937..6f1259ed82 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -19931,7 +19931,7 @@ fn coerce( if (inst_ty.ptrAddressSpace() != dest_info.@"addrspace") break :single_item; switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { .ok => {}, - .no_match => break :single_item, + else => break :single_item, } return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); } @@ -19951,7 +19951,7 @@ fn coerce( const dst_elem_type = dest_info.pointee_type; switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src)) { .ok => {}, - .no_match => break :src_array_ptr, + else => break :src_array_ptr, } switch (dest_info.size) { @@ -19990,7 +19990,7 @@ fn coerce( const dst_elem_type = dest_info.pointee_type; switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { .ok => {}, - .no_match => break :src_c_ptr, + else => break :src_c_ptr, } // TODO add safety check for null pointer return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); @@ -20034,7 +20034,7 @@ fn coerce( inst_src, )) { .ok => {}, - .no_match => break :p, + else => break :p, } if (inst_info.size == .Slice) { if (dest_info.sentinel == null or inst_info.sentinel == null or @@ -20124,7 +20124,7 @@ fn coerce( inst_src, )) { .ok => {}, - .no_match => break :p, + else => break :p, } if (dest_info.sentinel == null or inst_info.sentinel == null or @@ -20356,14 +20356,348 @@ fn coerce( return sema.addConstUndef(dest_ty); } - return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); + const msg = msg: { + const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); + errdefer msg.destroy(sema.gpa); + + try in_memory_result.report(sema, block, inst_src, msg); + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); } -const InMemoryCoercionResult = enum { +const InMemoryCoercionResult = union(enum) { ok, - no_match, + no_match: Pair, + int_mismatch: Int, + error_union_payload: PairAndChild, + array_len: IntPair, + array_sentinel: Sentinel, + array_elem: PairAndChild, + vector_len: IntPair, + vector_elem: PairAndChild, + optional_shape: Pair, + optional_child: PairAndChild, + from_anyerror, + missing_error: []const []const u8, + /// true if wanted is var args + fn_var_args: bool, + /// true if wanted is generic + fn_generic: bool, + fn_param_count: IntPair, + fn_param_noalias: IntPair, + fn_param_comptime: ComptimeParam, + fn_param: Param, + fn_cc: CC, + fn_return_type: PairAndChild, + ptr_child: PairAndChild, + ptr_addrspace: AddressSpace, + ptr_sentinel: Sentinel, + ptr_size: Size, + ptr_qualifiers: Qualifiers, + ptr_allowzero: Pair, + ptr_bit_range: BitRange, + ptr_alignment: IntPair, + + const Pair = struct { + actual: Type, + wanted: Type, + }; + + const PairAndChild = struct { + child: *InMemoryCoercionResult, + actual: Type, + wanted: Type, + }; + + const Param = struct { + child: *InMemoryCoercionResult, + actual: Type, + wanted: Type, + index: u64, + }; + + const ComptimeParam = struct { + index: u64, + wanted: bool, + }; + + const Sentinel = struct { + // unreachable_value indicates no sentinel + actual: Value, + wanted: Value, + ty: Type, + }; + + const Int = struct { + actual_signedness: std.builtin.Signedness, + wanted_signedness: std.builtin.Signedness, + actual_bits: u16, + wanted_bits: u16, + }; + + const IntPair = struct { + actual: u64, + wanted: u64, + }; + + const Size = struct { + actual: std.builtin.Type.Pointer.Size, + wanted: std.builtin.Type.Pointer.Size, + }; + + const Qualifiers = struct { + actual_const: bool, + wanted_const: bool, + actual_volatile: bool, + wanted_volatile: bool, + }; + + const AddressSpace = struct { + actual: std.builtin.AddressSpace, + wanted: std.builtin.AddressSpace, + }; + + const CC = struct { + actual: std.builtin.CallingConvention, + wanted: std.builtin.CallingConvention, + }; + + const BitRange = struct { + actual_host: u16, + wanted_host: u16, + actual_offset: u16, + wanted_offset: u16, + }; + + fn dupe(child: *const InMemoryCoercionResult, arena: Allocator) !*InMemoryCoercionResult { + const res = try arena.create(InMemoryCoercionResult); + res.* = child.*; + return res; + } + + fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { + var cur = res; + while (true) switch (cur.*) { + .ok => unreachable, + .no_match => |types| { + try sema.addDeclaredHereNote(msg, types.wanted); + try sema.addDeclaredHereNote(msg, types.actual); + break; + }, + .int_mismatch => |int| { + try sema.errNote(block, src, msg, "{s} {d}-bit int cannot represent all possible {s} {d}-bit values", .{ + @tagName(int.wanted_signedness), int.wanted_bits, @tagName(int.actual_signedness), int.actual_bits, + }); + break; + }, + .error_union_payload => |pair| { + try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .array_len => |lens| { + try sema.errNote(block, src, msg, "array of length {d} cannot cast into an array of length {d}", .{ + lens.actual, lens.wanted, + }); + break; + }, + .array_sentinel => |sentinel| { + if (sentinel.actual.tag() != .unreachable_value) { + try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ + sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), + }); + } else { + try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ + sentinel.wanted.fmtValue(sentinel.ty, sema.mod), + }); + } + break; + }, + .array_elem => |pair| { + try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .vector_len => |lens| { + try sema.errNote(block, src, msg, "vector of length {d} cannot cast into a vector of length {d}", .{ + lens.actual, lens.wanted, + }); + break; + }, + .vector_elem => |pair| { + try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .optional_shape => |pair| { + try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + break; + }, + .optional_child => |pair| { + try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .from_anyerror => { + try sema.errNote(block, src, msg, "global error set cannot cast into a smaller set", .{}); + break; + }, + .missing_error => |missing_errors| { + for (missing_errors) |err| { + try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); + } + break; + }, + .fn_var_args => |wanted_var_args| { + if (wanted_var_args) { + try sema.errNote(block, src, msg, "non-variadic function cannot cast into a variadic function", .{}); + } else { + try sema.errNote(block, src, msg, "variadic function cannot cast into a non-variadic function", .{}); + } + break; + }, + .fn_generic => |wanted_generic| { + if (wanted_generic) { + try sema.errNote(block, src, msg, "non-generic function cannot cast into a generic function", .{}); + } else { + try sema.errNote(block, src, msg, "generic function cannot cast into a non-generic function", .{}); + } + break; + }, + .fn_param_count => |lens| { + try sema.errNote(block, src, msg, "function with {d} parameters cannot cast into a function with {d} parameters", .{ + lens.actual, lens.wanted, + }); + break; + }, + .fn_param_noalias => |param| { + var index: u6 = 0; + var actual_noalias = false; + while (true) : (index += 1) { + if (param.actual << index != param.wanted << index) { + actual_noalias = (param.actual << index) == (1 << 31); + } + } + if (!actual_noalias) { + try sema.errNote(block, src, msg, "regular paramter {d} cannot cast into a noalias paramter", .{index}); + } else { + try sema.errNote(block, src, msg, "noalias paramter {d} cannot cast into a regular paramter", .{index}); + } + break; + }, + .fn_param_comptime => |param| { + if (param.wanted) { + try sema.errNote(block, src, msg, "non-comptime paramter {d} cannot cast into a comptime paramter", .{param.index}); + } else { + try sema.errNote(block, src, msg, "comptime paramter {d} cannot cast into a non-comptime paramter", .{param.index}); + } + break; + }, + .fn_param => |param| { + try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ + param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod), + }); + cur = param.child; + }, + .fn_cc => |cc| { + try sema.errNote(block, src, msg, "calling convention {s} cannot cast into calling convention {s}", .{ @tagName(cc.actual), @tagName(cc.wanted) }); + break; + }, + .fn_return_type => |pair| { + try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .ptr_child => |pair| { + try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + cur = pair.child; + }, + .ptr_addrspace => |@"addrspace"| { + try sema.errNote(block, src, msg, "address space '{s}' cannot cast into address space '{s}'", .{ @tagName(@"addrspace".actual), @tagName(@"addrspace".wanted) }); + break; + }, + .ptr_sentinel => |sentinel| { + if (sentinel.actual.tag() != .unreachable_value) { + try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ + sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), + }); + } else { + try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ + sentinel.wanted.fmtValue(sentinel.ty, sema.mod), + }); + } + break; + }, + .ptr_size => |size| { + try sema.errNote(block, src, msg, "a {s} pointer cannot cast into a {s} pointer", .{ pointerSizeString(size.actual), pointerSizeString(size.wanted) }); + break; + }, + .ptr_qualifiers => |qualifiers| { + const ok_const = !qualifiers.actual_const or qualifiers.wanted_const; + const ok_volatile = !qualifiers.actual_volatile or qualifiers.wanted_volatile; + if (!ok_const) { + try sema.errNote(block, src, msg, "cast discards const qualifier", .{}); + } else if (!ok_volatile) { + try sema.errNote(block, src, msg, "cast discards volatile qualifier", .{}); + } + break; + }, + .ptr_allowzero => |pair| { + const wanted_allow_zero = pair.wanted.ptrAllowsZero(); + const actual_allow_zero = pair.actual.ptrAllowsZero(); + if (actual_allow_zero and !wanted_allow_zero) { + try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + } else { + try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ + pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), + }); + } + break; + }, + .ptr_bit_range => |bit_range| { + if (bit_range.actual_host != bit_range.wanted_host) { + try sema.errNote(block, src, msg, "pointer host size '{}' cannot cast into pointer host size '{}'", .{ + bit_range.actual_host, bit_range.wanted_host, + }); + } + if (bit_range.actual_offset != bit_range.wanted_offset) { + try sema.errNote(block, src, msg, "pointer bit offset '{}' cannot cast into pointer bit offset '{}'", .{ + bit_range.actual_offset, bit_range.wanted_offset, + }); + } + break; + }, + .ptr_alignment => |pair| { + try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ + pair.actual, pair.wanted, + }); + break; + }, + }; + } }; +fn pointerSizeString(size: std.builtin.Type.Pointer.Size) []const u8 { + return switch (size) { + .One => "single", + .Many => "many", + .C => "C", + .Slice => unreachable, + }; +} + /// If pointers have the same representation in runtime memory, a bitcast AIR instruction /// may be used for the coercion. /// * `const` attribute can be gained @@ -20373,8 +20707,6 @@ const InMemoryCoercionResult = enum { /// * bit offset attributes must match exactly /// * `*`/`[*]` must match exactly, but `[*c]` matches either one /// * sentinel-terminated pointers can coerce into `[*]` -/// TODO improve this function to report recursive compile errors like it does in stage1. -/// look at the function types_match_const_cast_only fn coerceInMemoryAllowed( sema: *Sema, block: *Block, @@ -20392,11 +20724,17 @@ fn coerceInMemoryAllowed( if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { const dest_info = dest_ty.intInfo(target); const src_info = src_ty.intInfo(target); - if (dest_info.signedness == src_info.signedness and - dest_info.bits == src_info.bits) + if (dest_info.signedness != src_info.signedness or + dest_info.bits != src_info.bits) { - return .ok; + return InMemoryCoercionResult{ .int_mismatch = .{ + .actual_signedness = src_info.signedness, + .wanted_signedness = dest_info.signedness, + .actual_bits = src_info.bits, + .wanted_bits = dest_info.bits, + } }; } + return .ok; } // Differently-named floats with the same number of bits. @@ -20434,9 +20772,15 @@ fn coerceInMemoryAllowed( // Error Unions if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { - const child = try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionPayload(), src_ty.errorUnionPayload(), dest_is_mut, target, dest_src, src_src); - if (child == .no_match) { - return child; + const dest_payload = dest_ty.errorUnionPayload(); + const src_payload = src_ty.errorUnionPayload(); + const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); + if (child != .ok) { + return InMemoryCoercionResult{ .error_union_payload = .{ + .child = try child.dupe(sema.arena), + .actual = src_payload, + .wanted = dest_payload, + } }; } return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); } @@ -20447,57 +20791,89 @@ fn coerceInMemoryAllowed( } // Arrays - if (dest_tag == .Array and src_tag == .Array) arrays: { + if (dest_tag == .Array and src_tag == .Array) { const dest_info = dest_ty.arrayInfo(); const src_info = src_ty.arrayInfo(); - if (dest_info.len != src_info.len) break :arrays; + if (dest_info.len != src_info.len) { + return InMemoryCoercionResult{ .array_len = .{ + .actual = src_info.len, + .wanted = dest_info.len, + } }; + } const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src); - if (child == .no_match) { - return child; + if (child != .ok) { + return InMemoryCoercionResult{ .array_elem = .{ + .child = try child.dupe(sema.arena), + .actual = src_info.elem_type, + .wanted = dest_info.elem_type, + } }; } const ok_sent = dest_info.sentinel == null or (src_info.sentinel != null and dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); if (!ok_sent) { - return .no_match; + return InMemoryCoercionResult{ .array_sentinel = .{ + .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), + .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), + .ty = dest_info.elem_type, + } }; } return .ok; } // Vectors - if (dest_tag == .Vector and src_tag == .Vector) vectors: { + if (dest_tag == .Vector and src_tag == .Vector) { const dest_len = dest_ty.vectorLen(); const src_len = src_ty.vectorLen(); - if (dest_len != src_len) break :vectors; + if (dest_len != src_len) { + return InMemoryCoercionResult{ .vector_len = .{ + .actual = src_len, + .wanted = dest_len, + } }; + } const dest_elem_ty = dest_ty.scalarType(); const src_elem_ty = src_ty.scalarType(); const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); - if (child == .no_match) break :vectors; + if (child != .ok) { + return InMemoryCoercionResult{ .vector_elem = .{ + .child = try child.dupe(sema.arena), + .actual = src_elem_ty, + .wanted = dest_elem_ty, + } }; + } return .ok; } // Optionals - if (dest_tag == .Optional and src_tag == .Optional) optionals: { + if (dest_tag == .Optional and src_tag == .Optional) { if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { - // TODO "optional type child '{}' cannot cast into optional type '{}'" - return .no_match; + return InMemoryCoercionResult{ .optional_shape = .{ + .actual = src_ty, + .wanted = dest_ty, + } }; } const dest_child_type = dest_ty.optionalChild(&dest_buf); const src_child_type = src_ty.optionalChild(&src_buf); const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); - if (child == .no_match) { - // TODO "optional type child '{}' cannot cast into optional type child '{}'" - break :optionals; + if (child != .ok) { + return InMemoryCoercionResult{ .optional_child = .{ + .child = try child.dupe(sema.arena), + .actual = src_child_type, + .wanted = dest_child_type, + } }; } return .ok; } - return .no_match; + return InMemoryCoercionResult{ .no_match = .{ + .actual = dest_ty, + .wanted = src_ty, + } }; } fn coerceInMemoryAllowedErrorSets( @@ -20564,6 +20940,9 @@ fn coerceInMemoryAllowedErrorSets( } } + var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); + defer missing_error_buf.deinit(); + switch (src_ty.tag()) { .error_set_inferred => { const src_data = src_ty.castTag(.error_set_inferred).?.data; @@ -20572,15 +20951,21 @@ fn coerceInMemoryAllowedErrorSets( // src anyerror status might have changed after the resolution. if (src_ty.isAnyError()) { // dest_ty.isAnyError() == true is already checked for at this point. - return .no_match; + return .from_anyerror; } for (src_data.errors.keys()) |key| { if (!dest_ty.errorSetHasField(key)) { - return .no_match; + try missing_error_buf.append(key); } } + if (missing_error_buf.items.len != 0) { + return InMemoryCoercionResult{ + .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), + }; + } + return .ok; }, .error_set_single => { @@ -20588,37 +20973,52 @@ fn coerceInMemoryAllowedErrorSets( if (dest_ty.errorSetHasField(name)) { return .ok; } + const list = try sema.arena.alloc([]const u8, 1); + list[0] = name; + return InMemoryCoercionResult{ .missing_error = list }; }, .error_set_merged => { const names = src_ty.castTag(.error_set_merged).?.data.keys(); for (names) |name| { if (!dest_ty.errorSetHasField(name)) { - return .no_match; + try missing_error_buf.append(name); } } + if (missing_error_buf.items.len != 0) { + return InMemoryCoercionResult{ + .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), + }; + } + return .ok; }, .error_set => { const names = src_ty.castTag(.error_set).?.data.names.keys(); for (names) |name| { if (!dest_ty.errorSetHasField(name)) { - return .no_match; + try missing_error_buf.append(name); } } + if (missing_error_buf.items.len != 0) { + return InMemoryCoercionResult{ + .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), + }; + } + return .ok; }, .anyerror => switch (dest_ty.tag()) { - .error_set_inferred => return .no_match, // Caught by dest.isAnyError() above. - .error_set_single, .error_set_merged, .error_set => {}, + .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. + .error_set_single, .error_set_merged, .error_set => return .from_anyerror, .anyerror => unreachable, // Filtered out above. else => unreachable, }, else => unreachable, } - return .no_match; + unreachable; } fn coerceInMemoryAllowedFns( @@ -20634,44 +21034,67 @@ fn coerceInMemoryAllowedFns( const src_info = src_ty.fnInfo(); if (dest_info.is_var_args != src_info.is_var_args) { - return .no_match; + return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; } if (dest_info.is_generic != src_info.is_generic) { - return .no_match; + return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; + } + + if (dest_info.cc != src_info.cc) { + return InMemoryCoercionResult{ .fn_cc = .{ + .actual = src_info.cc, + .wanted = dest_info.cc, + } }; } if (!src_info.return_type.isNoReturn()) { const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); - if (rt == .no_match) { - return rt; + if (rt != .ok) { + return InMemoryCoercionResult{ .fn_return_type = .{ + .child = try rt.dupe(sema.arena), + .actual = src_info.return_type, + .wanted = dest_info.return_type, + } }; } } if (dest_info.param_types.len != src_info.param_types.len) { - return .no_match; + return InMemoryCoercionResult{ .fn_param_count = .{ + .actual = dest_info.param_types.len, + .wanted = dest_info.param_types.len, + } }; + } + + if (dest_info.noalias_bits != src_info.noalias_bits) { + return InMemoryCoercionResult{ .fn_param_noalias = .{ + .actual = dest_info.noalias_bits, + .wanted = dest_info.noalias_bits, + } }; } for (dest_info.param_types) |dest_param_ty, i| { const src_param_ty = src_info.param_types[i]; if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { - return .no_match; + return InMemoryCoercionResult{ .fn_param_comptime = .{ + .index = i, + .wanted = dest_info.comptime_params[i], + } }; } - // TODO: noalias - // Note: Cast direction is reversed here. const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); - if (param == .no_match) { - return param; + if (param != .ok) { + return InMemoryCoercionResult{ .fn_param = .{ + .child = try param.dupe(sema.arena), + .actual = src_param_ty, + .wanted = dest_param_ty, + .index = i, + } }; } } - if (dest_info.cc != src_info.cc) { - return .no_match; - } - return .ok; } @@ -20690,26 +21113,13 @@ fn coerceInMemoryAllowedPtrs( const dest_info = dest_ptr_ty.ptrInfo().data; const src_info = src_ptr_ty.ptrInfo().data; - const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); - if (child == .no_match) { - return child; - } - - if (dest_info.@"addrspace" != src_info.@"addrspace") { - return .no_match; - } - - const ok_sent = dest_info.sentinel == null or src_info.size == .C or - (src_info.sentinel != null and - dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); - if (!ok_sent) { - return .no_match; - } - const ok_ptr_size = src_info.size == dest_info.size or src_info.size == .C or dest_info.size == .C; if (!ok_ptr_size) { - return .no_match; + return InMemoryCoercionResult{ .ptr_size = .{ + .actual = src_info.size, + .wanted = dest_info.size, + } }; } const ok_cv_qualifiers = @@ -20717,7 +21127,28 @@ fn coerceInMemoryAllowedPtrs( (!src_info.@"volatile" or dest_info.@"volatile"); if (!ok_cv_qualifiers) { - return .no_match; + return InMemoryCoercionResult{ .ptr_qualifiers = .{ + .actual_const = !src_info.mutable, + .wanted_const = !dest_info.mutable, + .actual_volatile = src_info.@"volatile", + .wanted_volatile = dest_info.@"volatile", + } }; + } + + if (dest_info.@"addrspace" != src_info.@"addrspace") { + return InMemoryCoercionResult{ .ptr_addrspace = .{ + .actual = src_info.@"addrspace", + .wanted = dest_info.@"addrspace", + } }; + } + + const child = try sema.coerceInMemoryAllowed(block, dest_info.pointee_type, src_info.pointee_type, dest_info.mutable, target, dest_src, src_src); + if (child != .ok) { + return InMemoryCoercionResult{ .ptr_child = .{ + .child = try child.dupe(sema.arena), + .actual = src_info.pointee_type, + .wanted = dest_info.pointee_type, + } }; } const dest_allow_zero = dest_ty.ptrAllowsZero(); @@ -20727,13 +21158,32 @@ fn coerceInMemoryAllowedPtrs( (src_allow_zero or !dest_is_mut)) or (!dest_allow_zero and !src_allow_zero); if (!ok_allows_zero) { - return .no_match; + return InMemoryCoercionResult{ .ptr_allowzero = .{ + .actual = src_ty, + .wanted = dest_ty, + } }; } if (src_info.host_size != dest_info.host_size or src_info.bit_offset != dest_info.bit_offset) { - return .no_match; + return InMemoryCoercionResult{ .ptr_bit_range = .{ + .actual_host = src_info.host_size, + .wanted_host = dest_info.host_size, + .actual_offset = src_info.bit_offset, + .wanted_offset = dest_info.bit_offset, + } }; + } + + const ok_sent = dest_info.sentinel == null or src_info.size == .C or + (src_info.sentinel != null and + dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); + if (!ok_sent) { + return InMemoryCoercionResult{ .ptr_sentinel = .{ + .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), + .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), + .ty = dest_info.pointee_type, + } }; } // If both pointers have alignment 0, it means they both want ABI alignment. @@ -20758,7 +21208,10 @@ fn coerceInMemoryAllowedPtrs( dest_info.pointee_type.abiAlignment(target); if (dest_align > src_align) { - return .no_match; + return InMemoryCoercionResult{ .ptr_alignment = .{ + .actual = src_align, + .wanted = dest_align, + } }; } break :alignment; diff --git a/test/cases/compile_errors/address_of_number_literal.zig b/test/cases/compile_errors/address_of_number_literal.zig index 2d8380634a..2000561207 100644 --- a/test/cases/compile_errors/address_of_number_literal.zig +++ b/test/cases/compile_errors/address_of_number_literal.zig @@ -8,3 +8,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } // target=native // // :3:30: error: expected type '*const i32', found '*const comptime_int' +// :3:30: note: pointer type child 'comptime_int' cannot cast into pointer type child 'i32' diff --git a/test/cases/compile_errors/stage1/obj/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig b/test/cases/compile_errors/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig similarity index 55% rename from test/cases/compile_errors/stage1/obj/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig rename to test/cases/compile_errors/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig index 760866dd65..b553d492ae 100644 --- a/test/cases/compile_errors/stage1/obj/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig +++ b/test/cases/compile_errors/attempted_implicit_cast_from_const_T_to_array_len_1_T.zig @@ -7,8 +7,8 @@ export fn entry(byte: u8) void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32' -// tmp.zig:4:22: note: cast discards const qualifier +// :4:22: error: expected type '*[1]i32', found '*const i32' +// :4:22: note: cast discards const qualifier diff --git a/test/cases/compile_errors/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig b/test/cases/compile_errors/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig new file mode 100644 index 0000000000..36a17d734b --- /dev/null +++ b/test/cases/compile_errors/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig @@ -0,0 +1,15 @@ +const SmallErrorSet = error{A}; +export fn entry() void { + var x: SmallErrorSet!i32 = foo(); + _ = x; +} +fn foo() anyerror!i32 { + return error.B; +} + +// error +// backend=stage2 +// target=native +// +// :3:35: error: expected type 'error{A}!i32', found 'anyerror!i32' +// :3:35: note: global error set cannot cast into a smaller set diff --git a/test/cases/compile_errors/stage1/obj/cast_global_error_set_to_error_set.zig b/test/cases/compile_errors/cast_global_error_set_to_error_set.zig similarity index 52% rename from test/cases/compile_errors/stage1/obj/cast_global_error_set_to_error_set.zig rename to test/cases/compile_errors/cast_global_error_set_to_error_set.zig index be9487cc5a..39d9474016 100644 --- a/test/cases/compile_errors/stage1/obj/cast_global_error_set_to_error_set.zig +++ b/test/cases/compile_errors/cast_global_error_set_to_error_set.zig @@ -8,8 +8,8 @@ fn foo() anyerror { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:3:31: error: expected type 'SmallErrorSet', found 'anyerror' -// tmp.zig:3:31: note: cannot cast global error set into smaller set +// :3:31: error: expected type 'error{A}', found 'anyerror' +// :3:31: note: global error set cannot cast into a smaller set diff --git a/test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig b/test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig index 083d68ee40..f25a4a656b 100644 --- a/test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig +++ b/test/cases/compile_errors/casting_bit_offset_pointer_to_regular_pointer.zig @@ -19,3 +19,5 @@ export fn entry() usize { return @sizeOf(@TypeOf(&foo)); } // target=native // // :8:15: error: expected type '*const u3', found '*align(0:3:1) const u3' +// :8:15: note: pointer host size '1' cannot cast into pointer host size '0' +// :8:15: note: pointer bit offset '3' cannot cast into pointer bit offset '0' diff --git a/test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig b/test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig index 2ba566f221..44ae18ae8a 100644 --- a/test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig +++ b/test/cases/compile_errors/dont_implicit_cast_double_pointer_to_anyopaque.zig @@ -11,3 +11,4 @@ export fn entry() void { // target=native // // :5:28: error: expected type '*anyopaque', found '**u32' +// :5:28: note: pointer type child '*u32' cannot cast into pointer type child 'anyopaque' diff --git a/test/cases/compile_errors/error_note_for_function_parameter_incompatibility.zig b/test/cases/compile_errors/error_note_for_function_parameter_incompatibility.zig new file mode 100644 index 0000000000..c43df47dfd --- /dev/null +++ b/test/cases/compile_errors/error_note_for_function_parameter_incompatibility.zig @@ -0,0 +1,13 @@ +fn do_the_thing(func: *const fn (arg: i32) void) void { _ = func; } +fn bar(arg: bool) void { _ = arg; } +export fn entry() void { + do_the_thing(bar); +} + +// error +// backend=stage2 +// target=native +// +// :4:17: error: expected type '*const fn(i32) void', found '*const fn(bool) void' +// :4:17: note: pointer type child 'fn(bool) void' cannot cast into pointer type child 'fn(i32) void' +// :4:17: note: parameter 0 'bool' cannot cast into 'i32' diff --git a/test/cases/compile_errors/stage1/obj/implicit_cast_of_error_set_not_a_subset.zig b/test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig similarity index 56% rename from test/cases/compile_errors/stage1/obj/implicit_cast_of_error_set_not_a_subset.zig rename to test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig index 5958a41639..0a182343b9 100644 --- a/test/cases/compile_errors/stage1/obj/implicit_cast_of_error_set_not_a_subset.zig +++ b/test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig @@ -9,8 +9,8 @@ fn foo(set1: Set1) void { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:7:19: error: expected type 'Set2', found 'Set1' -// tmp.zig:1:23: note: 'error.B' not a member of destination error set +// :7:19: error: expected type 'error{A,C}', found 'error{A,B}' +// :7:19: note: 'error.B' not a member of destination error set diff --git a/test/cases/compile_errors/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig b/test/cases/compile_errors/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig new file mode 100644 index 0000000000..ecdc6c14c9 --- /dev/null +++ b/test/cases/compile_errors/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig @@ -0,0 +1,26 @@ +export fn entry() void { + var slice: []const u8 = "aoeu"; + const opt_many_ptr: [*]const u8 = slice.ptr; + var ptr_opt_many_ptr = &opt_many_ptr; + var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + ptr_opt_many_ptr = c_ptr; +} +export fn entry2() void { + var buf: [4]u8 = "aoeu".*; + var slice: []u8 = &buf; + var opt_many_ptr: [*]u8 = slice.ptr; + var ptr_opt_many_ptr = &opt_many_ptr; + var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr; + _ = c_ptr; +} + +// error +// backend=stage2 +// target=native +// +// :6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8' +// :6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8' +// :6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8' +// :13:35: error: expected type '[*c][*c]const u8', found '*[*]u8' +// :13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8' +// :13:35: note: mutable '[*]u8' allows illegal null values stored to type '[*c]const u8' diff --git a/test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig b/test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig index b1930cb548..2f7686c93d 100644 --- a/test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig +++ b/test/cases/compile_errors/implicitly_casting_enum_to_tag_type.zig @@ -15,3 +15,4 @@ export fn entry() void { // target=native // // :9:22: error: expected type 'u2', found 'tmp.Small' +// :1:15: note: enum declared here diff --git a/test/cases/compile_errors/incompatible_sentinels.zig b/test/cases/compile_errors/incompatible_sentinels.zig new file mode 100644 index 0000000000..a2ed320e18 --- /dev/null +++ b/test/cases/compile_errors/incompatible_sentinels.zig @@ -0,0 +1,29 @@ +// Note: One of the error messages here is backwards. It would be nice to fix, but that's not +// going to stop me from merging this branch which fixes a bunch of other stuff. +export fn entry1(ptr: [*:255]u8) [*:0]u8 { + return ptr; +} +export fn entry2(ptr: [*]u8) [*:0]u8 { + return ptr; +} +export fn entry3() void { + var array: [2:0]u8 = [_:255]u8{ 1, 2 }; + _ = array; +} +export fn entry4() void { + var array: [2:0]u8 = [_]u8{ 1, 2 }; + _ = array; +} + +// error +// backend=stage2 +// target=native +// +// :4:12: error: expected type '[*:0]u8', found '[*:255]u8' +// :4:12: note: pointer sentinel '255' cannot cast into pointer sentinel '0' +// :7:12: error: expected type '[*:0]u8', found '[*]u8' +// :7:12: note: destination pointer requires '0' sentinel +// :10:35: error: expected type '[2:0]u8', found '[2:255]u8' +// :10:35: note: array sentinel '255' cannot cast into array sentinel '0' +// :14:31: error: expected type '[2:0]u8', found '[2]u8' +// :14:31: note: destination array requires '0' sentinel diff --git a/test/cases/compile_errors/incorrect_return_type.zig b/test/cases/compile_errors/incorrect_return_type.zig index b37cbebc7f..7b678b68e3 100644 --- a/test/cases/compile_errors/incorrect_return_type.zig +++ b/test/cases/compile_errors/incorrect_return_type.zig @@ -19,3 +19,5 @@ // target=native // // :8:16: error: expected type 'tmp.A', found 'tmp.B' +// :10:12: note: struct declared here +// :4:12: note: struct declared here diff --git a/test/cases/compile_errors/invalid_address_space_coercion.zig b/test/cases/compile_errors/invalid_address_space_coercion.zig index fd49aecb32..1c42260a0e 100644 --- a/test/cases/compile_errors/invalid_address_space_coercion.zig +++ b/test/cases/compile_errors/invalid_address_space_coercion.zig @@ -11,3 +11,4 @@ pub fn main() void { // target=x86_64-linux,x86_64-macos // // :2:12: error: expected type '*i32', found '*addrspace(.gs) i32' +// :2:12: note: address space 'gs' cannot cast into address space 'generic' diff --git a/test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig b/test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig index ce2f64169b..0041976683 100644 --- a/test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig +++ b/test/cases/compile_errors/invalid_cast_from_integral_type_to_enum.zig @@ -15,3 +15,4 @@ fn foo(x: usize) void { // target=native // // :9:10: error: expected type 'usize', found 'tmp.E' +// :1:11: note: enum declared here diff --git a/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig b/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig index 1560dcc46a..fb8e0d5fd4 100644 --- a/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig +++ b/test/cases/compile_errors/invalid_pointer_keeps_address_space_when_taking_address_of_dereference.zig @@ -11,3 +11,4 @@ pub fn main() void { // target=x86_64-linux,x86_64-macos // // :2:12: error: expected type '*i32', found '*addrspace(.gs) i32' +// :2:12: note: address space 'gs' cannot cast into address space 'generic' diff --git a/test/cases/compile_errors/not_an_enum_type.zig b/test/cases/compile_errors/not_an_enum_type.zig index 6868cf7dc0..063ee8a8d8 100644 --- a/test/cases/compile_errors/not_an_enum_type.zig +++ b/test/cases/compile_errors/not_an_enum_type.zig @@ -17,3 +17,4 @@ const ExpectedVarDeclOrFn = struct {}; // target=native // // :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type' +// :8:1: note: enum declared here diff --git a/test/cases/compile_errors/passing_a_not-aligned-enough_pointer_to_cmpxchg.zig b/test/cases/compile_errors/passing_a_not-aligned-enough_pointer_to_cmpxchg.zig index 3ddd24f7a9..6deb06b1ff 100644 --- a/test/cases/compile_errors/passing_a_not-aligned-enough_pointer_to_cmpxchg.zig +++ b/test/cases/compile_errors/passing_a_not-aligned-enough_pointer_to_cmpxchg.zig @@ -10,3 +10,4 @@ export fn entry() bool { // target=native // // :4:31: error: expected type '*i32', found '*align(1) i32' +// :4:31: note: pointer alignment '1' cannot cast into pointer alignment '4' diff --git a/test/cases/compile_errors/pointer_with_different_address_spaces.zig b/test/cases/compile_errors/pointer_with_different_address_spaces.zig index b16c4a4e64..3f8c961174 100644 --- a/test/cases/compile_errors/pointer_with_different_address_spaces.zig +++ b/test/cases/compile_errors/pointer_with_different_address_spaces.zig @@ -11,3 +11,4 @@ export fn entry2() void { // target=x86_64-linux,x86_64-macos // // :2:12: error: expected type '*addrspace(.fs) i32', found '*addrspace(.gs) i32' +// :2:12: note: address space 'gs' cannot cast into address space 'fs' diff --git a/test/cases/compile_errors/pointers_with_different_address_spaces.zig b/test/cases/compile_errors/pointers_with_different_address_spaces.zig index 210c252893..2a7698d0d9 100644 --- a/test/cases/compile_errors/pointers_with_different_address_spaces.zig +++ b/test/cases/compile_errors/pointers_with_different_address_spaces.zig @@ -11,3 +11,4 @@ pub fn main() void { // target=x86_64-linux,x86_64-macos // // :2:13: error: expected type '*i32', found '*addrspace(.gs) i32' +// :2:13: note: address space 'gs' cannot cast into address space 'generic' diff --git a/test/cases/compile_errors/shifting_RHS_is_log2_of_LHS_int_bit_width.zig b/test/cases/compile_errors/shifting_RHS_is_log2_of_LHS_int_bit_width.zig index a2104d1aa6..5141062a0b 100644 --- a/test/cases/compile_errors/shifting_RHS_is_log2_of_LHS_int_bit_width.zig +++ b/test/cases/compile_errors/shifting_RHS_is_log2_of_LHS_int_bit_width.zig @@ -7,3 +7,4 @@ export fn entry(x: u8, y: u8) u8 { // target=native // // :2:17: error: expected type 'u3', found 'u8' +// :2:17: note: unsigned 3-bit int cannot represent all possible unsigned 8-bit values diff --git a/test/cases/compile_errors/slice_sentinel_mismatch-2.zig b/test/cases/compile_errors/slice_sentinel_mismatch-2.zig new file mode 100644 index 0000000000..b1ff905e26 --- /dev/null +++ b/test/cases/compile_errors/slice_sentinel_mismatch-2.zig @@ -0,0 +1,12 @@ +fn foo() [:0]u8 { + var x: []u8 = undefined; + return x; +} +comptime { _ = foo; } + +// error +// backend=stage2 +// target=native +// +// :3:12: error: expected type '[:0]u8', found '[]u8' +// :3:12: note: destination pointer requires '0' sentinel diff --git a/test/cases/compile_errors/stage1/obj/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig b/test/cases/compile_errors/stage1/obj/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig deleted file mode 100644 index 08962afc85..0000000000 --- a/test/cases/compile_errors/stage1/obj/cast_error_union_of_global_error_set_to_error_union_of_smaller_error_set.zig +++ /dev/null @@ -1,16 +0,0 @@ -const SmallErrorSet = error{A}; -export fn entry() void { - var x: SmallErrorSet!i32 = foo(); - _ = x; -} -fn foo() anyerror!i32 { - return error.B; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'anyerror!i32' -// tmp.zig:3:35: note: error set 'anyerror' cannot cast into error set 'SmallErrorSet' -// tmp.zig:3:35: note: cannot cast global error set into smaller set diff --git a/test/cases/compile_errors/stage1/obj/error_note_for_function_parameter_incompatibility.zig b/test/cases/compile_errors/stage1/obj/error_note_for_function_parameter_incompatibility.zig deleted file mode 100644 index edc421d8f4..0000000000 --- a/test/cases/compile_errors/stage1/obj/error_note_for_function_parameter_incompatibility.zig +++ /dev/null @@ -1,12 +0,0 @@ -fn do_the_thing(func: fn (arg: i32) void) void { _ = func; } -fn bar(arg: bool) void { _ = arg; } -export fn entry() void { - do_the_thing(bar); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void -// tmp.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32' diff --git a/test/cases/compile_errors/stage1/obj/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig b/test/cases/compile_errors/stage1/obj/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig deleted file mode 100644 index 760bab41da..0000000000 --- a/test/cases/compile_errors/stage1/obj/implicit_casting_C_pointers_which_would_mess_up_null_semantics.zig +++ /dev/null @@ -1,26 +0,0 @@ -export fn entry() void { - var slice: []const u8 = "aoeu"; - const opt_many_ptr: [*]const u8 = slice.ptr; - var ptr_opt_many_ptr = &opt_many_ptr; - var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; - ptr_opt_many_ptr = c_ptr; -} -export fn entry2() void { - var buf: [4]u8 = "aoeu".*; - var slice: []u8 = &buf; - var opt_many_ptr: [*]u8 = slice.ptr; - var ptr_opt_many_ptr = &opt_many_ptr; - var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr; - _ = c_ptr; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8' -// tmp.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8' -// tmp.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8' -// tmp.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8' -// tmp.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8' -// tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8' diff --git a/test/cases/compile_errors/stage1/obj/incompatible_sentinels.zig b/test/cases/compile_errors/stage1/obj/incompatible_sentinels.zig deleted file mode 100644 index a292ae3d7c..0000000000 --- a/test/cases/compile_errors/stage1/obj/incompatible_sentinels.zig +++ /dev/null @@ -1,29 +0,0 @@ -// Note: One of the error messages here is backwards. It would be nice to fix, but that's not -// going to stop me from merging this branch which fixes a bunch of other stuff. -export fn entry1(ptr: [*:255]u8) [*:0]u8 { - return ptr; -} -export fn entry2(ptr: [*]u8) [*:0]u8 { - return ptr; -} -export fn entry3() void { - var array: [2:0]u8 = [_:255]u8{ 1, 2 }; - _ = array; -} -export fn entry4() void { - var array: [2:0]u8 = [_]u8{ 1, 2 }; - _ = array; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:12: error: expected type '[*:0]u8', found '[*:255]u8' -// tmp.zig:4:12: note: destination pointer requires a terminating '0' sentinel, but source pointer has a terminating '255' sentinel -// tmp.zig:7:12: error: expected type '[*:0]u8', found '[*]u8' -// tmp.zig:7:12: note: destination pointer requires a terminating '0' sentinel -// tmp.zig:10:35: error: expected type '[2:255]u8', found '[2:0]u8' -// tmp.zig:10:35: note: destination array requires a terminating '255' sentinel, but source array has a terminating '0' sentinel -// tmp.zig:14:31: error: expected type '[2:0]u8', found '[2]u8' -// tmp.zig:14:31: note: destination array requires a terminating '0' sentinel diff --git a/test/cases/compile_errors/stage1/obj/slice_sentinel_mismatch-2.zig b/test/cases/compile_errors/stage1/obj/slice_sentinel_mismatch-2.zig deleted file mode 100644 index 5f8d312a3c..0000000000 --- a/test/cases/compile_errors/stage1/obj/slice_sentinel_mismatch-2.zig +++ /dev/null @@ -1,12 +0,0 @@ -fn foo() [:0]u8 { - var x: []u8 = undefined; - return x; -} -comptime { _ = foo; } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:12: error: expected type '[:0]u8', found '[]u8' -// tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel diff --git a/test/cases/compile_errors/stage1/obj/type_checking_function_pointers.zig b/test/cases/compile_errors/stage1/obj/type_checking_function_pointers.zig deleted file mode 100644 index b88b6bdb52..0000000000 --- a/test/cases/compile_errors/stage1/obj/type_checking_function_pointers.zig +++ /dev/null @@ -1,13 +0,0 @@ -fn a(b: fn (*const u8) void) void { - b('a'); -} -fn c(d: u8) void {_ = d;} -export fn entry() void { - a(c); -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:6:7: error: expected type 'fn(*const u8) void', found 'fn(u8) void' diff --git a/test/cases/compile_errors/type_checking_function_pointers.zig b/test/cases/compile_errors/type_checking_function_pointers.zig new file mode 100644 index 0000000000..e6c7a7a1f7 --- /dev/null +++ b/test/cases/compile_errors/type_checking_function_pointers.zig @@ -0,0 +1,15 @@ +fn a(b: *const fn (*const u8) void) void { + _ = b; +} +fn c(d: u8) void {_ = d;} +export fn entry() void { + a(c); +} + +// error +// backend=stage2 +// target=native +// +// :6:6: error: expected type '*const fn(*const u8) void', found '*const fn(u8) void' +// :6:6: note: pointer type child 'fn(u8) void' cannot cast into pointer type child 'fn(*const u8) void' +// :6:6: note: parameter 0 'u8' cannot cast into '*const u8' diff --git a/test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig b/test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig index 125ded95d6..1e7acb55b8 100644 --- a/test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig +++ b/test/cases/compile_errors/type_mismatch_in_C_prototype_with_varargs.zig @@ -11,3 +11,5 @@ export fn main() void { // target=native // // :5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void' +// :5:22: note: parameter 0 '[*:0]u8' cannot cast into '[*c]u8' +// :5:22: note: '[*c]u8' could have null values which are illegal in type '[*:0]u8' diff --git a/test/cases/compile_errors/wrong_type_for_reify_type.zig b/test/cases/compile_errors/wrong_type_for_reify_type.zig index 7f712b441f..b88f6563b5 100644 --- a/test/cases/compile_errors/wrong_type_for_reify_type.zig +++ b/test/cases/compile_errors/wrong_type_for_reify_type.zig @@ -7,3 +7,4 @@ export fn entry() void { // target=native // // :2:15: error: expected type 'builtin.Type', found 'comptime_int' +// :?:?: note: union declared here