mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
Sema: add detailed error notes to coerceInMemoryAllowed
This commit is contained in:
parent
b9ed072278
commit
b9f01bc394
599
src/Sema.zig
599
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;
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
@ -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
|
||||
@ -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'
|
||||
@ -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
|
||||
|
||||
29
test/cases/compile_errors/incompatible_sentinels.zig
Normal file
29
test/cases/compile_errors/incompatible_sentinels.zig
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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
|
||||
|
||||
12
test/cases/compile_errors/slice_sentinel_mismatch-2.zig
Normal file
12
test/cases/compile_errors/slice_sentinel_mismatch-2.zig
Normal file
@ -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
|
||||
@ -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
|
||||
@ -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'
|
||||
@ -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'
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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'
|
||||
@ -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'
|
||||
@ -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'
|
||||
|
||||
@ -7,3 +7,4 @@ export fn entry() void {
|
||||
// target=native
|
||||
//
|
||||
// :2:15: error: expected type 'builtin.Type', found 'comptime_int'
|
||||
// :?:?: note: union declared here
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user