mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 08:02:32 +00:00
Merge pull request #15726 from mlugg/feat/peer-type-resolution-but-better
Sema: rewrite peer type resolution
This commit is contained in:
commit
496320d935
@ -4568,6 +4568,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {
|
||||
/// * int <=> int
|
||||
/// * int <=> enum
|
||||
/// * enum_literal => enum
|
||||
/// * float <=> float
|
||||
/// * ptr <=> ptr
|
||||
/// * opt ptr <=> ptr
|
||||
/// * opt ptr <=> opt ptr
|
||||
@ -4579,6 +4580,7 @@ pub fn sliceLen(ip: *const InternPool, i: Index) Index {
|
||||
/// * error set => error union
|
||||
/// * payload => error union
|
||||
/// * fn <=> fn
|
||||
/// * aggregate <=> aggregate (where children can also be coerced)
|
||||
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
|
||||
const old_ty = ip.typeOf(val);
|
||||
if (old_ty == new_ty) return val;
|
||||
@ -4623,6 +4625,23 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
|
||||
else => if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, int, new_ty),
|
||||
},
|
||||
.float => |float| switch (ip.indexToKey(new_ty)) {
|
||||
.simple_type => |simple| switch (simple) {
|
||||
.f16,
|
||||
.f32,
|
||||
.f64,
|
||||
.f80,
|
||||
.f128,
|
||||
.c_longdouble,
|
||||
.comptime_float,
|
||||
=> return ip.get(gpa, .{ .float = .{
|
||||
.ty = new_ty,
|
||||
.storage = float.storage,
|
||||
} }),
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
|
||||
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
|
||||
.enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
|
||||
@ -4688,6 +4707,80 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
|
||||
.ty = new_ty,
|
||||
.val = error_union.val,
|
||||
} }),
|
||||
.aggregate => |aggregate| {
|
||||
const new_len = @intCast(usize, ip.aggregateTypeLen(new_ty));
|
||||
direct: {
|
||||
const old_ty_child = switch (ip.indexToKey(old_ty)) {
|
||||
inline .array_type, .vector_type => |seq_type| seq_type.child,
|
||||
.anon_struct_type, .struct_type => break :direct,
|
||||
else => unreachable,
|
||||
};
|
||||
const new_ty_child = switch (ip.indexToKey(new_ty)) {
|
||||
inline .array_type, .vector_type => |seq_type| seq_type.child,
|
||||
.anon_struct_type, .struct_type => break :direct,
|
||||
else => unreachable,
|
||||
};
|
||||
if (old_ty_child != new_ty_child) break :direct;
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe here
|
||||
switch (aggregate.storage) {
|
||||
.bytes => |bytes| {
|
||||
const bytes_copy = try gpa.dupe(u8, bytes[0..new_len]);
|
||||
defer gpa.free(bytes_copy);
|
||||
return ip.get(gpa, .{ .aggregate = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .bytes = bytes_copy },
|
||||
} });
|
||||
},
|
||||
.elems => |elems| {
|
||||
const elems_copy = try gpa.dupe(InternPool.Index, elems[0..new_len]);
|
||||
defer gpa.free(elems_copy);
|
||||
return ip.get(gpa, .{ .aggregate = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .elems = elems_copy },
|
||||
} });
|
||||
},
|
||||
.repeated_elem => |elem| {
|
||||
return ip.get(gpa, .{ .aggregate = .{
|
||||
.ty = new_ty,
|
||||
.storage = .{ .repeated_elem = elem },
|
||||
} });
|
||||
},
|
||||
}
|
||||
}
|
||||
// Direct approach failed - we must recursively coerce elems
|
||||
const agg_elems = try gpa.alloc(InternPool.Index, new_len);
|
||||
defer gpa.free(agg_elems);
|
||||
// First, fill the vector with the uncoerced elements. We do this to avoid key
|
||||
// lifetime issues, since it'll allow us to avoid referencing `aggregate` after we
|
||||
// begin interning elems.
|
||||
switch (aggregate.storage) {
|
||||
.bytes => {
|
||||
// We have to intern each value here, so unfortunately we can't easily avoid
|
||||
// the repeated indexToKey calls.
|
||||
for (agg_elems, 0..) |*elem, i| {
|
||||
const x = ip.indexToKey(val).aggregate.storage.bytes[i];
|
||||
elem.* = try ip.get(gpa, .{ .int = .{
|
||||
.ty = .u8_type,
|
||||
.storage = .{ .u64 = x },
|
||||
} });
|
||||
}
|
||||
},
|
||||
.elems => |elems| @memcpy(agg_elems, elems[0..new_len]),
|
||||
.repeated_elem => |elem| @memset(agg_elems, elem),
|
||||
}
|
||||
// Now, coerce each element to its new type.
|
||||
for (agg_elems, 0..) |*elem, i| {
|
||||
const new_elem_ty = switch (ip.indexToKey(new_ty)) {
|
||||
inline .array_type, .vector_type => |seq_type| seq_type.child,
|
||||
.anon_struct_type => |anon_struct_type| anon_struct_type.types[i],
|
||||
.struct_type => |struct_type| ip.structPtr(struct_type.index.unwrap().?)
|
||||
.fields.values()[i].ty.toIntern(),
|
||||
else => unreachable,
|
||||
};
|
||||
elem.* = try ip.getCoerced(gpa, elem.*, new_elem_ty);
|
||||
}
|
||||
return ip.get(gpa, .{ .aggregate = .{ .ty = new_ty, .storage = .{ .elems = agg_elems } } });
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
}
|
||||
|
@ -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);
|
||||
|
2075
src/Sema.zig
2075
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…
Reference in New Issue
Block a user