mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
Sema: rewrite peer type resolution
The existing logic for peer type resolution was quite convoluted and buggy. This rewrite makes it much more resilient, readable, and extensible. The algorithm works by first iterating over the types to select a "strategy", then applying that strategy, possibly applying peer resolution recursively. Several new tests have been added to cover cases which the old logic did not correctly handle. Resolves: #15138 Resolves: #15644 Resolves: #15693 Resolves: #15709 Resolves: #15752
This commit is contained in:
parent
854f26ad8a
commit
c9531eb833
@ -6978,7 +6978,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
|
||||
assert(sign);
|
||||
// Protect against overflow in the following negation.
|
||||
if (x == std.math.minInt(i64)) return 64;
|
||||
return Type.smallestUnsignedBits(@intCast(u64, -x - 1)) + 1;
|
||||
return Type.smallestUnsignedBits(@intCast(u64, -(x + 1))) + 1;
|
||||
},
|
||||
.u64 => |x| {
|
||||
return Type.smallestUnsignedBits(x) + @boolToInt(sign);
|
||||
|
||||
2067
src/Sema.zig
2067
src/Sema.zig
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,9 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
const mem = std.mem;
|
||||
const maxInt = std.math.maxInt;
|
||||
const native_endian = builtin.target.cpu.arch.endian();
|
||||
@ -1609,3 +1612,610 @@ test "coercion from single-item pointer to @as to slice" {
|
||||
|
||||
try expect(t[0] == 1);
|
||||
}
|
||||
|
||||
test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest(comptime T: type, comptime s: T) !void {
|
||||
var a: [:s]const T = @intToPtr(*const [2:s]T, 0x1000);
|
||||
var b: []T = @intToPtr(*[3]T, 0x2000);
|
||||
comptime assert(@TypeOf(a, b) == []const T);
|
||||
comptime assert(@TypeOf(b, a) == []const T);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const R = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(R, @intToPtr(*const [2:s]T, 0x1000)), r1);
|
||||
try expectEqual(@as(R, @intToPtr(*const [3]T, 0x2000)), r2);
|
||||
}
|
||||
};
|
||||
|
||||
try S.doTheTest(u8, 0);
|
||||
try S.doTheTest(?*anyopaque, null);
|
||||
}
|
||||
|
||||
test "peer type resolution: float and comptime-known fixed-width integer" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
const i: u8 = 100;
|
||||
var f: f32 = 1.234;
|
||||
comptime assert(@TypeOf(i, f) == f32);
|
||||
comptime assert(@TypeOf(f, i) == f32);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) i else f;
|
||||
const r2 = if (t) f else i;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, 100.0), r1);
|
||||
try expectEqual(@as(T, 1.234), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: same array type with sentinel" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: [2:0]u32 = .{ 0, 1 };
|
||||
var b: [2:0]u32 = .{ 2, 3 };
|
||||
comptime assert(@TypeOf(a, b) == [2:0]u32);
|
||||
comptime assert(@TypeOf(b, a) == [2:0]u32);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 0, 1 }, r1);
|
||||
try expectEqual(T{ 2, 3 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: array with sentinel and array without sentinel" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: [2:0]u32 = .{ 0, 1 };
|
||||
var b: [2]u32 = .{ 2, 3 };
|
||||
comptime assert(@TypeOf(a, b) == [2]u32);
|
||||
comptime assert(@TypeOf(b, a) == [2]u32);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 0, 1 }, r1);
|
||||
try expectEqual(T{ 2, 3 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: array and vector with same child type" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var arr: [2]u32 = .{ 0, 1 };
|
||||
var vec: @Vector(2, u32) = .{ 2, 3 };
|
||||
comptime assert(@TypeOf(arr, vec) == @Vector(2, u32));
|
||||
comptime assert(@TypeOf(vec, arr) == @Vector(2, u32));
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) arr else vec;
|
||||
const r2 = if (t) vec else arr;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 0, 1 }, r1);
|
||||
try expectEqual(T{ 2, 3 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: array with smaller child type and vector with larger child type" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var arr: [2]u8 = .{ 0, 1 };
|
||||
var vec: @Vector(2, u64) = .{ 2, 3 };
|
||||
comptime assert(@TypeOf(arr, vec) == @Vector(2, u64));
|
||||
comptime assert(@TypeOf(vec, arr) == @Vector(2, u64));
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) arr else vec;
|
||||
const r2 = if (t) vec else arr;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 0, 1 }, r1);
|
||||
try expectEqual(T{ 2, 3 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: error union and optional of same type" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
const E = error{Foo};
|
||||
var a: E!*u8 = error.Foo;
|
||||
var b: ?*u8 = null;
|
||||
comptime assert(@TypeOf(a, b) == E!?*u8);
|
||||
comptime assert(@TypeOf(b, a) == E!?*u8);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, error.Foo), r1);
|
||||
try expectEqual(@as(T, null), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: C pointer and @TypeOf(null)" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: [*c]c_int = 0x1000;
|
||||
const b = null;
|
||||
comptime assert(@TypeOf(a, b) == [*c]c_int);
|
||||
comptime assert(@TypeOf(b, a) == [*c]c_int);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, 0x1000), r1);
|
||||
try expectEqual(@as(T, null), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: three-way resolution combines error set and optional" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
const E = error{Foo};
|
||||
var a: E = error.Foo;
|
||||
var b: *const [5:0]u8 = @intToPtr(*const [5:0]u8, 0x1000);
|
||||
var c: ?[*:0]u8 = null;
|
||||
comptime assert(@TypeOf(a, b, c) == E!?[*:0]const u8);
|
||||
comptime assert(@TypeOf(a, c, b) == E!?[*:0]const u8);
|
||||
comptime assert(@TypeOf(b, a, c) == E!?[*:0]const u8);
|
||||
comptime assert(@TypeOf(b, c, a) == E!?[*:0]const u8);
|
||||
comptime assert(@TypeOf(c, a, b) == E!?[*:0]const u8);
|
||||
comptime assert(@TypeOf(c, b, a) == E!?[*:0]const u8);
|
||||
|
||||
var x: u8 = 0;
|
||||
const r1 = switch (x) {
|
||||
0 => a,
|
||||
1 => b,
|
||||
else => c,
|
||||
};
|
||||
const r2 = switch (x) {
|
||||
0 => b,
|
||||
1 => a,
|
||||
else => c,
|
||||
};
|
||||
const r3 = switch (x) {
|
||||
0 => c,
|
||||
1 => a,
|
||||
else => b,
|
||||
};
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, error.Foo), r1);
|
||||
try expectEqual(@as(T, @intToPtr([*:0]u8, 0x1000)), r2);
|
||||
try expectEqual(@as(T, null), r3);
|
||||
}
|
||||
|
||||
test "peer type resolution: vector and optional vector" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: ?@Vector(3, u32) = .{ 0, 1, 2 };
|
||||
var b: @Vector(3, u32) = .{ 3, 4, 5 };
|
||||
comptime assert(@TypeOf(a, b) == ?@Vector(3, u32));
|
||||
comptime assert(@TypeOf(b, a) == ?@Vector(3, u32));
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, .{ 0, 1, 2 }), r1);
|
||||
try expectEqual(@as(T, .{ 3, 4, 5 }), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: optional fixed-width int and comptime_int" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: ?i32 = 42;
|
||||
const b: comptime_int = 50;
|
||||
comptime assert(@TypeOf(a, b) == ?i32);
|
||||
comptime assert(@TypeOf(b, a) == ?i32);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(@as(T, 42), r1);
|
||||
try expectEqual(@as(T, 50), r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: array and tuple" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var arr: [3]i32 = .{ 1, 2, 3 };
|
||||
const tup = .{ 4, 5, 6 };
|
||||
|
||||
comptime assert(@TypeOf(arr, tup) == [3]i32);
|
||||
comptime assert(@TypeOf(tup, arr) == [3]i32);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) arr else tup;
|
||||
const r2 = if (t) tup else arr;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 1, 2, 3 }, r1);
|
||||
try expectEqual(T{ 4, 5, 6 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: vector and tuple" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var vec: @Vector(3, i32) = .{ 1, 2, 3 };
|
||||
const tup = .{ 4, 5, 6 };
|
||||
|
||||
comptime assert(@TypeOf(vec, tup) == @Vector(3, i32));
|
||||
comptime assert(@TypeOf(tup, vec) == @Vector(3, i32));
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) vec else tup;
|
||||
const r2 = if (t) tup else vec;
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 1, 2, 3 }, r1);
|
||||
try expectEqual(T{ 4, 5, 6 }, r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: vector and array and tuple" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var vec: @Vector(2, i8) = .{ 10, 20 };
|
||||
var arr: [2]i8 = .{ 30, 40 };
|
||||
const tup = .{ 50, 60 };
|
||||
|
||||
comptime assert(@TypeOf(vec, arr, tup) == @Vector(2, i8));
|
||||
comptime assert(@TypeOf(vec, tup, arr) == @Vector(2, i8));
|
||||
comptime assert(@TypeOf(arr, vec, tup) == @Vector(2, i8));
|
||||
comptime assert(@TypeOf(arr, tup, vec) == @Vector(2, i8));
|
||||
comptime assert(@TypeOf(tup, vec, arr) == @Vector(2, i8));
|
||||
comptime assert(@TypeOf(tup, arr, vec) == @Vector(2, i8));
|
||||
|
||||
var x: u8 = 0;
|
||||
const r1 = switch (x) {
|
||||
0 => vec,
|
||||
1 => arr,
|
||||
else => tup,
|
||||
};
|
||||
const r2 = switch (x) {
|
||||
0 => arr,
|
||||
1 => vec,
|
||||
else => tup,
|
||||
};
|
||||
const r3 = switch (x) {
|
||||
0 => tup,
|
||||
1 => vec,
|
||||
else => arr,
|
||||
};
|
||||
|
||||
const T = @TypeOf(r1);
|
||||
|
||||
try expectEqual(T{ 10, 20 }, r1);
|
||||
try expectEqual(T{ 30, 40 }, r2);
|
||||
try expectEqual(T{ 50, 60 }, r3);
|
||||
}
|
||||
|
||||
test "peer type resolution: empty tuple pointer and slice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: [:0]const u8 = "Hello";
|
||||
var b = &.{};
|
||||
|
||||
comptime assert(@TypeOf(a, b) == []const u8);
|
||||
comptime assert(@TypeOf(b, a) == []const u8);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
try expectEqualSlices(u8, "Hello", r1);
|
||||
try expectEqualSlices(u8, "", r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: tuple pointer and slice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: [:0]const u8 = "Hello";
|
||||
var b = &.{ @as(u8, 'x'), @as(u8, 'y'), @as(u8, 'z') };
|
||||
|
||||
comptime assert(@TypeOf(a, b) == []const u8);
|
||||
comptime assert(@TypeOf(b, a) == []const u8);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
try expectEqualSlices(u8, "Hello", r1);
|
||||
try expectEqualSlices(u8, "xyz", r2);
|
||||
}
|
||||
|
||||
test "peer type resolution: tuple pointer and optional slice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: ?[:0]const u8 = null;
|
||||
var b = &.{ @as(u8, 'x'), @as(u8, 'y'), @as(u8, 'z') };
|
||||
|
||||
comptime assert(@TypeOf(a, b) == ?[]const u8);
|
||||
comptime assert(@TypeOf(b, a) == ?[]const u8);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
try expectEqual(@as(?[]const u8, null), r1);
|
||||
try expectEqualSlices(u8, "xyz", r2 orelse "");
|
||||
}
|
||||
|
||||
test "peer type resolution: many compatible pointers" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var buf = "foo-3".*;
|
||||
|
||||
var vals = .{
|
||||
@as([*]const u8, "foo-0"),
|
||||
@as([*:0]const u8, "foo-1"),
|
||||
@as([*:0]const u8, "foo-2"),
|
||||
@as([*]u8, &buf),
|
||||
@as(*const [5]u8, "foo-4"),
|
||||
};
|
||||
|
||||
// Check every possible permutation of types in @TypeOf
|
||||
@setEvalBranchQuota(5000);
|
||||
comptime var perms = 0; // check the loop is hitting every permutation
|
||||
inline for (0..5) |i_0| {
|
||||
inline for (0..5) |i_1| {
|
||||
if (i_1 == i_0) continue;
|
||||
inline for (0..5) |i_2| {
|
||||
if (i_2 == i_0 or i_2 == i_1) continue;
|
||||
inline for (0..5) |i_3| {
|
||||
if (i_3 == i_0 or i_3 == i_1 or i_3 == i_2) continue;
|
||||
inline for (0..5) |i_4| {
|
||||
if (i_4 == i_0 or i_4 == i_1 or i_4 == i_2 or i_4 == i_3) continue;
|
||||
perms += 1;
|
||||
comptime assert(@TypeOf(
|
||||
vals[i_0],
|
||||
vals[i_1],
|
||||
vals[i_2],
|
||||
vals[i_3],
|
||||
vals[i_4],
|
||||
) == [*]const u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
comptime assert(perms == 5 * 4 * 3 * 2 * 1);
|
||||
|
||||
var x: u8 = 0;
|
||||
inline for (0..5) |i| {
|
||||
const r = switch (x) {
|
||||
0 => vals[i],
|
||||
1 => vals[0],
|
||||
2 => vals[1],
|
||||
3 => vals[2],
|
||||
4 => vals[3],
|
||||
else => vals[4],
|
||||
};
|
||||
const expected = switch (i) {
|
||||
0 => "foo-0",
|
||||
1 => "foo-1",
|
||||
2 => "foo-2",
|
||||
3 => "foo-3",
|
||||
4 => "foo-4",
|
||||
else => unreachable,
|
||||
};
|
||||
try expectEqualSlices(u8, expected, std.mem.span(@ptrCast([*:0]const u8, r)));
|
||||
}
|
||||
}
|
||||
|
||||
test "peer type resolution: tuples with comptime fields" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
const a = .{ 1, 2 };
|
||||
const b = .{ @as(u32, 3), @as(i16, 4) };
|
||||
|
||||
// TODO: tuple type equality doesn't work properly yet
|
||||
const ti1 = @typeInfo(@TypeOf(a, b));
|
||||
const ti2 = @typeInfo(@TypeOf(b, a));
|
||||
inline for (.{ ti1, ti2 }) |ti| {
|
||||
const s = ti.Struct;
|
||||
comptime assert(s.is_tuple);
|
||||
comptime assert(s.fields.len == 2);
|
||||
comptime assert(s.fields[0].type == u32);
|
||||
comptime assert(s.fields[1].type == i16);
|
||||
}
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
try expectEqual(@as(u32, 1), r1[0]);
|
||||
try expectEqual(@as(i16, 2), r1[1]);
|
||||
|
||||
try expectEqual(@as(u32, 3), r2[0]);
|
||||
try expectEqual(@as(i16, 4), r2[1]);
|
||||
}
|
||||
|
||||
test "peer type resolution: C pointer and many pointer" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var buf = "hello".*;
|
||||
|
||||
var a: [*c]u8 = &buf;
|
||||
var b: [*:0]const u8 = "world";
|
||||
|
||||
comptime assert(@TypeOf(a, b) == [*c]const u8);
|
||||
comptime assert(@TypeOf(b, a) == [*c]const u8);
|
||||
|
||||
var t = true;
|
||||
const r1 = if (t) a else b;
|
||||
const r2 = if (t) b else a;
|
||||
|
||||
try expectEqual(r1, a);
|
||||
try expectEqual(r2, b);
|
||||
}
|
||||
|
||||
test "peer type resolution: pointer attributes are combined correctly" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
|
||||
|
||||
var buf_a align(4) = "foo".*;
|
||||
var buf_b align(4) = "bar".*;
|
||||
var buf_c align(4) = "baz".*;
|
||||
|
||||
var a: [*:0]align(4) const u8 = &buf_a;
|
||||
var b: *align(2) volatile [3:0]u8 = &buf_b;
|
||||
var c: [*:0]align(4) u8 = &buf_c;
|
||||
|
||||
comptime assert(@TypeOf(a, b, c) == [*:0]align(2) const volatile u8);
|
||||
comptime assert(@TypeOf(a, c, b) == [*:0]align(2) const volatile u8);
|
||||
comptime assert(@TypeOf(b, a, c) == [*:0]align(2) const volatile u8);
|
||||
comptime assert(@TypeOf(b, c, a) == [*:0]align(2) const volatile u8);
|
||||
comptime assert(@TypeOf(c, a, b) == [*:0]align(2) const volatile u8);
|
||||
comptime assert(@TypeOf(c, b, a) == [*:0]align(2) const volatile u8);
|
||||
|
||||
var x: u8 = 0;
|
||||
const r1 = switch (x) {
|
||||
0 => a,
|
||||
1 => b,
|
||||
else => c,
|
||||
};
|
||||
const r2 = switch (x) {
|
||||
0 => b,
|
||||
1 => a,
|
||||
else => c,
|
||||
};
|
||||
const r3 = switch (x) {
|
||||
0 => c,
|
||||
1 => a,
|
||||
else => b,
|
||||
};
|
||||
|
||||
try expectEqualSlices(u8, std.mem.span(@volatileCast(r1)), "foo");
|
||||
try expectEqualSlices(u8, std.mem.span(@volatileCast(r2)), "bar");
|
||||
try expectEqualSlices(u8, std.mem.span(@volatileCast(r3)), "baz");
|
||||
}
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
export fn inconsistentChildType() void {
|
||||
var x: ?i32 = undefined;
|
||||
const y: comptime_int = 10;
|
||||
_ = (x == y);
|
||||
}
|
||||
export fn optionalToOptional() void {
|
||||
var x: ?i32 = undefined;
|
||||
var y: ?i32 = undefined;
|
||||
_ = (x == y);
|
||||
}
|
||||
export fn optionalVector() void {
|
||||
var x: ?@Vector(10, i32) = undefined;
|
||||
var y: @Vector(10, i32) = undefined;
|
||||
_ = (x == y);
|
||||
}
|
||||
export fn optionalVector2() void {
|
||||
var x: ?@Vector(10, i32) = undefined;
|
||||
var y: @Vector(11, i32) = undefined;
|
||||
_ = (x == y);
|
||||
}
|
||||
export fn invalidChildType() void {
|
||||
var x: ?[3]i32 = undefined;
|
||||
var y: [3]i32 = undefined;
|
||||
_ = (x == y);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// :4:12: error: incompatible types: '?i32' and 'comptime_int'
|
||||
// :4:10: note: type '?i32' here
|
||||
// :4:15: note: type 'comptime_int' here
|
||||
// :19:12: error: incompatible types: '?@Vector(10, i32)' and '@Vector(11, i32)'
|
||||
// :19:10: note: type '?@Vector(10, i32)' here
|
||||
// :19:15: note: type '@Vector(11, i32)' here
|
||||
// :24:12: error: operator == not allowed for type '?[3]i32'
|
||||
@ -0,0 +1,11 @@
|
||||
export fn entry() void {
|
||||
var x: ?[3]i32 = undefined;
|
||||
var y: [3]i32 = undefined;
|
||||
_ = (x == y);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// :4:12: error: operator == not allowed for type '?[3]i32'
|
||||
50
test/cases/compile_errors/invalid_peer_type_resolution.zig
Normal file
50
test/cases/compile_errors/invalid_peer_type_resolution.zig
Normal file
@ -0,0 +1,50 @@
|
||||
export fn optionalVector() void {
|
||||
var x: ?@Vector(10, i32) = undefined;
|
||||
var y: @Vector(11, i32) = undefined;
|
||||
_ = @TypeOf(x, y);
|
||||
}
|
||||
export fn badTupleField() void {
|
||||
var x = .{ @as(u8, 0), @as(u32, 1) };
|
||||
var y = .{ @as(u8, 1), "hello" };
|
||||
_ = @TypeOf(x, y);
|
||||
}
|
||||
export fn badNestedField() void {
|
||||
const x = .{ .foo = "hi", .bar = .{ 0, 1 } };
|
||||
const y = .{ .foo = "hello", .bar = .{ 2, "hi" } };
|
||||
_ = @TypeOf(x, y);
|
||||
}
|
||||
export fn incompatiblePointers() void {
|
||||
const x: []const u8 = "foo";
|
||||
const y: [*:0]const u8 = "bar";
|
||||
_ = @TypeOf(x, y);
|
||||
}
|
||||
export fn incompatiblePointers4() void {
|
||||
const a: *const [5]u8 = "hello";
|
||||
const b: *const [3:0]u8 = "foo";
|
||||
const c: []const u8 = "baz"; // The conflict must be reported against this element!
|
||||
const d: [*]const u8 = "bar";
|
||||
_ = @TypeOf(a, b, c, d);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// :4:9: error: incompatible types: '?@Vector(10, i32)' and '@Vector(11, i32)'
|
||||
// :4:17: note: type '?@Vector(10, i32)' here
|
||||
// :4:20: note: type '@Vector(11, i32)' here
|
||||
// :9:9: error: struct field '1' has conflicting types
|
||||
// :9:9: note: incompatible types: 'u32' and '*const [5:0]u8'
|
||||
// :9:17: note: type 'u32' here
|
||||
// :9:20: note: type '*const [5:0]u8' here
|
||||
// :14:9: error: struct field 'bar' has conflicting types
|
||||
// :14:9: note: struct field '1' has conflicting types
|
||||
// :14:9: note: incompatible types: 'comptime_int' and '*const [2:0]u8'
|
||||
// :14:17: note: type 'comptime_int' here
|
||||
// :14:20: note: type '*const [2:0]u8' here
|
||||
// :19:9: error: incompatible types: '[]const u8' and '[*:0]const u8'
|
||||
// :19:17: note: type '[]const u8' here
|
||||
// :19:20: note: type '[*:0]const u8' here
|
||||
// :26:9: error: incompatible types: '[]const u8' and '[*]const u8'
|
||||
// :26:23: note: type '[]const u8' here
|
||||
// :26:26: note: type '[*]const u8' here
|
||||
Loading…
x
Reference in New Issue
Block a user