commit ffa700ee58cd29dafe2bbdfe78a4bd4f7bab0674 (tree)
parent 6e42d45dccf4ba6fa07082db1cb820897d36924f
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sun, 12 Jun 2022 17:45:57 -0400
Merge pull request #11837 from Vexu/stage2
Fix (nearly) all stage2 crashes when testing stdlib
Diffstat:
43 files changed, 501 insertions(+), 626 deletions(-)
diff --git a/ci/zinc/linux_test.sh b/ci/zinc/linux_test.sh
@@ -59,6 +59,7 @@ stage2/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted f
# * https://github.com/ziglang/zig/issues/11367 (and corresponding workaround in compiler source)
# * https://github.com/ziglang/zig/pull/11492#issuecomment-1112871321
stage2/bin/zig build test-behavior -fqemu -fwasmtime
+stage2/bin/zig test lib/std/std.zig --zig-lib-dir lib
$ZIG build test-behavior -fqemu -fwasmtime -Domit-stage2
$ZIG build test-compiler-rt -fqemu -fwasmtime
diff --git a/lib/std/bit_set.zig b/lib/std/bit_set.zig
@@ -1330,6 +1330,7 @@ fn testStaticBitSet(comptime Set: type) !void {
}
test "IntegerBitSet" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
try testStaticBitSet(IntegerBitSet(0));
try testStaticBitSet(IntegerBitSet(1));
try testStaticBitSet(IntegerBitSet(2));
@@ -1341,6 +1342,7 @@ test "IntegerBitSet" {
}
test "ArrayBitSet" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
if (@import("builtin").cpu.arch == .aarch64) {
// https://github.com/ziglang/zig/issues/9879
return error.SkipZigTest;
@@ -1355,6 +1357,7 @@ test "ArrayBitSet" {
}
test "DynamicBitSetUnmanaged" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const allocator = std.testing.allocator;
var a = try DynamicBitSetUnmanaged.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
@@ -1395,6 +1398,7 @@ test "DynamicBitSetUnmanaged" {
}
test "DynamicBitSet" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const allocator = std.testing.allocator;
var a = try DynamicBitSet.initEmpty(allocator, 300);
try testing.expectEqual(@as(usize, 0), a.count());
diff --git a/lib/std/compress.zig b/lib/std/compress.zig
@@ -5,7 +5,6 @@ pub const gzip = @import("compress/gzip.zig");
pub const zlib = @import("compress/zlib.zig");
test {
- if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
_ = deflate;
_ = gzip;
_ = zlib;
diff --git a/lib/std/compress/deflate/compressor.zig b/lib/std/compress/deflate/compressor.zig
@@ -254,7 +254,10 @@ pub fn Compressor(comptime WriterType: anytype) type {
// Inner writer wrapped in a HuffmanBitWriter
hm_bw: hm_bw.HuffmanBitWriter(WriterType) = undefined,
- bulk_hasher: fn ([]u8, []u32) u32,
+ bulk_hasher: if (@import("builtin").zig_backend == .stage1)
+ fn ([]u8, []u32) u32
+ else
+ *const fn ([]u8, []u32) u32,
sync: bool, // requesting flush
best_speed_enc: *fast.DeflateFast, // Encoder for best_speed
diff --git a/lib/std/compress/deflate/compressor_test.zig b/lib/std/compress/deflate/compressor_test.zig
@@ -122,11 +122,8 @@ fn testToFromWithLevelAndLimit(level: deflate.Compression, input: []const u8, li
try expect(compressed.items.len <= limit);
}
- var decomp = try decompressor(
- testing.allocator,
- io.fixedBufferStream(compressed.items).reader(),
- null,
- );
+ var fib = io.fixedBufferStream(compressed.items);
+ var decomp = try decompressor(testing.allocator, fib.reader(), null);
defer decomp.deinit();
var decompressed = try testing.allocator.alloc(u8, input.len);
@@ -136,7 +133,9 @@ fn testToFromWithLevelAndLimit(level: deflate.Compression, input: []const u8, li
try expect(read == input.len);
try expect(mem.eql(u8, input, decompressed));
- try testSync(level, input);
+ if (builtin.zig_backend == .stage1) {
+ try testSync(level, input);
+ }
}
fn testToFromWithLimit(input: []const u8, limit: [11]u32) !void {
@@ -475,21 +474,16 @@ test "inflate reset" {
try comp.close();
}
- var decomp = try decompressor(
- testing.allocator,
- io.fixedBufferStream(compressed_strings[0].items).reader(),
- null,
- );
+ var fib = io.fixedBufferStream(compressed_strings[0].items);
+ var decomp = try decompressor(testing.allocator, fib.reader(), null);
defer decomp.deinit();
var decompressed_0: []u8 = try decomp.reader()
.readAllAlloc(testing.allocator, math.maxInt(usize));
defer testing.allocator.free(decompressed_0);
- try decomp.reset(
- io.fixedBufferStream(compressed_strings[1].items).reader(),
- null,
- );
+ fib = io.fixedBufferStream(compressed_strings[1].items);
+ try decomp.reset(fib.reader(), null);
var decompressed_1: []u8 = try decomp.reader()
.readAllAlloc(testing.allocator, math.maxInt(usize));
@@ -530,21 +524,16 @@ test "inflate reset dictionary" {
try comp.close();
}
- var decomp = try decompressor(
- testing.allocator,
- io.fixedBufferStream(compressed_strings[0].items).reader(),
- dict,
- );
+ var fib = io.fixedBufferStream(compressed_strings[0].items);
+ var decomp = try decompressor(testing.allocator, fib.reader(), dict);
defer decomp.deinit();
var decompressed_0: []u8 = try decomp.reader()
.readAllAlloc(testing.allocator, math.maxInt(usize));
defer testing.allocator.free(decompressed_0);
- try decomp.reset(
- io.fixedBufferStream(compressed_strings[1].items).reader(),
- dict,
- );
+ fib = io.fixedBufferStream(compressed_strings[1].items);
+ try decomp.reset(fib.reader(), dict);
var decompressed_1: []u8 = try decomp.reader()
.readAllAlloc(testing.allocator, math.maxInt(usize));
diff --git a/lib/std/compress/deflate/decompressor.zig b/lib/std/compress/deflate/decompressor.zig
@@ -334,7 +334,10 @@ pub fn Decompressor(comptime ReaderType: type) type {
// Next step in the decompression,
// and decompression state.
- step: fn (*Self) Error!void,
+ step: if (@import("builtin").zig_backend == .stage1)
+ fn (*Self) Error!void
+ else
+ *const fn (*Self) Error!void,
step_state: DecompressorState,
final: bool,
err: ?Error,
@@ -479,7 +482,13 @@ pub fn Decompressor(comptime ReaderType: type) type {
}
pub fn close(self: *Self) ?Error {
- if (self.err == Error.EndOfStreamWithNoError) {
+ if (@import("builtin").zig_backend == .stage1) {
+ if (self.err == Error.EndOfStreamWithNoError) {
+ return null;
+ }
+ return self.err;
+ }
+ if (self.err == @as(?Error, error.EndOfStreamWithNoError)) {
return null;
}
return self.err;
@@ -920,7 +929,8 @@ test "truncated input" {
};
for (tests) |t| {
- var r = io.fixedBufferStream(t.input).reader();
+ var fib = io.fixedBufferStream(t.input);
+ const r = fib.reader();
var z = try decompressor(testing.allocator, r, null);
defer z.deinit();
var zr = z.reader();
@@ -959,7 +969,8 @@ test "Go non-regression test for 9842" {
};
for (tests) |t| {
- const reader = std.io.fixedBufferStream(t.input).reader();
+ var fib = std.io.fixedBufferStream(t.input);
+ const reader = fib.reader();
var decomp = try decompressor(testing.allocator, reader, null);
defer decomp.deinit();
@@ -1017,7 +1028,8 @@ test "inflate A Tale of Two Cities (1859) intro" {
\\
;
- const reader = std.io.fixedBufferStream(&compressed).reader();
+ var fib = std.io.fixedBufferStream(&compressed);
+ const reader = fib.reader();
var decomp = try decompressor(testing.allocator, reader, null);
defer decomp.deinit();
@@ -1082,7 +1094,8 @@ test "fuzzing" {
fn decompress(input: []const u8) !void {
const allocator = testing.allocator;
- const reader = std.io.fixedBufferStream(input).reader();
+ var fib = std.io.fixedBufferStream(input);
+ const reader = fib.reader();
var decomp = try decompressor(allocator, reader, null);
defer decomp.deinit();
var output = try decomp.reader().readAllAlloc(allocator, math.maxInt(usize));
diff --git a/lib/std/compress/deflate/deflate_fast_test.zig b/lib/std/compress/deflate/deflate_fast_test.zig
@@ -78,11 +78,8 @@ test "best speed" {
var decompressed = try testing.allocator.alloc(u8, want.items.len);
defer testing.allocator.free(decompressed);
- var decomp = try inflate.decompressor(
- testing.allocator,
- io.fixedBufferStream(compressed.items).reader(),
- null,
- );
+ var fib = io.fixedBufferStream(compressed.items);
+ var decomp = try inflate.decompressor(testing.allocator, fib.reader(), null);
defer decomp.deinit();
var read = try decomp.reader().readAll(decompressed);
@@ -122,13 +119,13 @@ test "best speed max match offset" {
// zeros1 is between 0 and 30 zeros.
// The difference between the two abc's will be offset, which
// is max_match_offset plus or minus a small adjustment.
- var src_len: usize = @intCast(usize, offset + abc.len + @intCast(i32, extra));
+ var src_len: usize = @intCast(usize, offset + @as(i32, abc.len) + @intCast(i32, extra));
var src = try testing.allocator.alloc(u8, src_len);
defer testing.allocator.free(src);
mem.copy(u8, src, abc);
if (!do_match_before) {
- var src_offset: usize = @intCast(usize, offset - xyz.len);
+ var src_offset: usize = @intCast(usize, offset - @as(i32, xyz.len));
mem.copy(u8, src[src_offset..], xyz);
}
var src_offset: usize = @intCast(usize, offset);
@@ -149,11 +146,8 @@ test "best speed max match offset" {
var decompressed = try testing.allocator.alloc(u8, src.len);
defer testing.allocator.free(decompressed);
- var decomp = try inflate.decompressor(
- testing.allocator,
- io.fixedBufferStream(compressed.items).reader(),
- null,
- );
+ var fib = io.fixedBufferStream(compressed.items);
+ var decomp = try inflate.decompressor(testing.allocator, fib.reader(), null);
defer decomp.deinit();
var read = try decomp.reader().readAll(decompressed);
_ = decomp.close();
diff --git a/lib/std/crypto/argon2.zig b/lib/std/crypto/argon2.zig
@@ -897,6 +897,7 @@ test "kdf" {
}
test "phc format hasher" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const allocator = std.testing.allocator;
const password = "testpass";
@@ -912,6 +913,7 @@ test "phc format hasher" {
}
test "password hash and password verify" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const allocator = std.testing.allocator;
const password = "testpass";
diff --git a/lib/std/crypto/bcrypt.zig b/lib/std/crypto/bcrypt.zig
@@ -802,6 +802,7 @@ test "bcrypt crypt format" {
}
test "bcrypt phc format" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const hash_options = HashOptions{
.params = .{ .rounds_log = 5 },
.encoding = .phc,
diff --git a/lib/std/crypto/phc_encoding.zig b/lib/std/crypto/phc_encoding.zig
@@ -260,6 +260,7 @@ fn kvSplit(str: []const u8) !struct { key: []const u8, value: []const u8 } {
}
test "phc format - encoding/decoding" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const Input = struct {
str: []const u8,
HashResult: type,
diff --git a/lib/std/crypto/scrypt.zig b/lib/std/crypto/scrypt.zig
@@ -683,6 +683,7 @@ test "unix-scrypt" {
}
test "crypt format" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const str = "$7$C6..../....SodiumChloride$kBGj9fHznVYFQMEn/qDCfrDevf9YDtcDdKvEqHJLV8D";
const params = try crypt_format.deserialize(crypt_format.HashResult(32), str);
var buf: [str.len]u8 = undefined;
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
@@ -2111,7 +2111,6 @@ test "slice" {
}
test "escape non-printable" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest;
try expectFmt("abc", "{s}", .{fmtSliceEscapeLower("abc")});
try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")});
try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")});
@@ -2148,7 +2147,6 @@ test "cstr" {
}
test "filesize" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest;
try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeDec(42)});
try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeBin(42)});
try expectFmt("file size: 63MB\n", "file size: {}\n", .{fmtIntSizeDec(63 * 1000 * 1000)});
@@ -2192,18 +2190,22 @@ test "enum" {
}
test "non-exhaustive enum" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const Enum = enum(u16) {
One = 0x000f,
Two = 0xbeef,
_,
};
- try expectFmt("enum: Enum.One\n", "enum: {}\n", .{Enum.One});
- try expectFmt("enum: Enum.Two\n", "enum: {}\n", .{Enum.Two});
- try expectFmt("enum: Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
- try expectFmt("enum: Enum.One\n", "enum: {x}\n", .{Enum.One});
- try expectFmt("enum: Enum.Two\n", "enum: {x}\n", .{Enum.Two});
- try expectFmt("enum: Enum.Two\n", "enum: {X}\n", .{Enum.Two});
- try expectFmt("enum: Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {}\n", .{Enum.One});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {}\n", .{Enum.Two});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(4660)\n", "enum: {}\n", .{@intToEnum(Enum, 0x1234)});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {x}\n", .{Enum.One});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {x}\n", .{Enum.Two});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {X}\n", .{Enum.Two});
+ try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(1234)\n", "enum: {x}\n", .{@intToEnum(Enum, 0x1234)});
}
test "float.scientific" {
@@ -2223,6 +2225,7 @@ test "float.scientific.precision" {
}
test "float.special" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
try expectFmt("f64: nan", "f64: {}", .{math.nan_f64});
// negative nan is not defined by IEE 754,
// and ARM thus normalizes it to positive nan
@@ -2234,6 +2237,7 @@ test "float.special" {
}
test "float.hexadecimal.special" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
try expectFmt("f64: nan", "f64: {x}", .{math.nan_f64});
// negative nan is not defined by IEE 754,
// and ARM thus normalizes it to positive nan
@@ -2359,6 +2363,10 @@ test "custom" {
}
test "struct" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const S = struct {
a: u32,
b: anyerror,
@@ -2369,7 +2377,7 @@ test "struct" {
.b = error.Unused,
};
- try expectFmt("S{ .a = 456, .b = error.Unused }", "{}", .{inst});
+ try expectFmt("fmt.test.struct.S{ .a = 456, .b = error.Unused }", "{}", .{inst});
// Tuples
try expectFmt("{ }", "{}", .{.{}});
try expectFmt("{ -1 }", "{}", .{.{-1}});
@@ -2377,6 +2385,10 @@ test "struct" {
}
test "union" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const TU = union(enum) {
float: f32,
int: u32,
@@ -2396,17 +2408,21 @@ test "union" {
const uu_inst = UU{ .int = 456 };
const eu_inst = EU{ .float = 321.123 };
- try expectFmt("TU{ .int = 123 }", "{}", .{tu_inst});
+ try expectFmt("fmt.test.union.TU{ .int = 123 }", "{}", .{tu_inst});
var buf: [100]u8 = undefined;
const uu_result = try bufPrint(buf[0..], "{}", .{uu_inst});
- try std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@"));
+ try std.testing.expect(mem.eql(u8, uu_result[0..18], "fmt.test.union.UU@"));
const eu_result = try bufPrint(buf[0..], "{}", .{eu_inst});
- try std.testing.expect(mem.eql(u8, eu_result[0..3], "EU@"));
+ try std.testing.expect(mem.eql(u8, eu_result[0..18], "fmt.test.union.EU@"));
}
test "enum" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const E = enum {
One,
Two,
@@ -2415,10 +2431,14 @@ test "enum" {
const inst = E.Two;
- try expectFmt("E.Two", "{}", .{inst});
+ try expectFmt("fmt.test.enum.E.Two", "{}", .{inst});
}
test "struct.self-referential" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const S = struct {
const SelfType = @This();
a: ?*SelfType,
@@ -2429,10 +2449,14 @@ test "struct.self-referential" {
};
inst.a = &inst;
- try expectFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", .{inst});
+ try expectFmt("fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ .a = fmt.test.struct.self-referential.S{ ... } } } }", "{}", .{inst});
}
test "struct.zero-size" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const A = struct {
fn foo() void {}
};
@@ -2444,11 +2468,10 @@ test "struct.zero-size" {
const a = A{};
const b = B{ .a = a, .c = 0 };
- try expectFmt("B{ .a = A{ }, .c = 0 }", "{}", .{b});
+ try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b});
}
test "bytes.hex" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest;
const some_bytes = "\xCA\xFE\xBA\xBE";
try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)});
try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)});
@@ -2480,7 +2503,6 @@ pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 {
}
test "hexToBytes" {
- if (builtin.zig_backend != .stage1) return error.SkipZigTest;
var buf: [32]u8 = undefined;
try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))});
try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))});
@@ -2512,6 +2534,10 @@ test "formatFloatValue with comptime_float" {
}
test "formatType max_depth" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
const Vec2 = struct {
const SelfType = @This();
x: f32,
@@ -2562,19 +2588,19 @@ test "formatType max_depth" {
var buf: [1000]u8 = undefined;
var fbs = std.io.fixedBufferStream(&buf);
try formatType(inst, "", FormatOptions{}, fbs.writer(), 0);
- try std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ ... }"));
+ try std.testing.expect(mem.eql(u8, fbs.getWritten(), "fmt.test.formatType max_depth.S{ ... }"));
fbs.reset();
try formatType(inst, "", FormatOptions{}, fbs.writer(), 1);
- try std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
+ try std.testing.expect(mem.eql(u8, fbs.getWritten(), "fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }"));
fbs.reset();
try formatType(inst, "", FormatOptions{}, fbs.writer(), 2);
- try std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ try std.testing.expect(mem.eql(u8, fbs.getWritten(), "fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }"));
fbs.reset();
try formatType(inst, "", FormatOptions{}, fbs.writer(), 3);
- try std.testing.expect(mem.eql(u8, fbs.getWritten(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
+ try std.testing.expect(mem.eql(u8, fbs.getWritten(), "fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }"));
}
test "positional" {
diff --git a/lib/std/io/stream_source.zig b/lib/std/io/stream_source.zig
@@ -114,7 +114,6 @@ test "StreamSource (mutable buffer)" {
}
test "StreamSource (const buffer)" {
- if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
const buffer: [64]u8 = "Hello, World!".* ++ ([1]u8{0xAA} ** 51);
var source = StreamSource{ .const_buffer = std.io.fixedBufferStream(&buffer) };
diff --git a/lib/std/math/copysign.zig b/lib/std/math/copysign.zig
@@ -13,6 +13,7 @@ pub fn copysign(magnitude: anytype, sign: @TypeOf(magnitude)) @TypeOf(magnitude)
}
test "math.copysign" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
try expect(copysign(@as(T, 1.0), @as(T, 1.0)) == 1.0);
try expect(copysign(@as(T, 2.0), @as(T, -2.0)) == -2.0);
diff --git a/lib/std/math/signbit.zig b/lib/std/math/signbit.zig
@@ -10,6 +10,7 @@ pub fn signbit(x: anytype) bool {
}
test "math.signbit" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
try expect(!signbit(@as(T, 0.0)));
try expect(!signbit(@as(T, 1.0)));
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
@@ -2080,6 +2080,7 @@ fn testReadIntImpl() !void {
}
test "writeIntSlice" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
try testWriteIntImpl();
comptime try testWriteIntImpl();
}
diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig
@@ -286,6 +286,7 @@ const PQlt = PriorityQueue(u32, void, lessThan);
const PQgt = PriorityQueue(u32, void, greaterThan);
test "std.PriorityQueue: add and remove min heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -304,6 +305,7 @@ test "std.PriorityQueue: add and remove min heap" {
}
test "std.PriorityQueue: add and remove same min heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -353,6 +355,7 @@ test "std.PriorityQueue: peek" {
}
test "std.PriorityQueue: sift up with odd indices" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
@@ -367,6 +370,7 @@ test "std.PriorityQueue: sift up with odd indices" {
}
test "std.PriorityQueue: addSlice" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
const items = [_]u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
@@ -412,6 +416,7 @@ test "std.PriorityQueue: fromOwnedSlice" {
}
test "std.PriorityQueue: add and remove max heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQgt.init(testing.allocator, {});
defer queue.deinit();
@@ -430,6 +435,7 @@ test "std.PriorityQueue: add and remove max heap" {
}
test "std.PriorityQueue: add and remove same max heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQgt.init(testing.allocator, {});
defer queue.deinit();
@@ -470,6 +476,7 @@ test "std.PriorityQueue: iterator" {
}
test "std.PriorityQueue: remove at index" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -505,6 +512,7 @@ test "std.PriorityQueue: iterator while empty" {
}
test "std.PriorityQueue: shrinkAndFree" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -528,6 +536,7 @@ test "std.PriorityQueue: shrinkAndFree" {
}
test "std.PriorityQueue: update min heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -543,6 +552,7 @@ test "std.PriorityQueue: update min heap" {
}
test "std.PriorityQueue: update same min heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -559,6 +569,7 @@ test "std.PriorityQueue: update same min heap" {
}
test "std.PriorityQueue: update max heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQgt.init(testing.allocator, {});
defer queue.deinit();
@@ -574,6 +585,7 @@ test "std.PriorityQueue: update max heap" {
}
test "std.PriorityQueue: update same max heap" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQgt.init(testing.allocator, {});
defer queue.deinit();
@@ -590,6 +602,7 @@ test "std.PriorityQueue: update same max heap" {
}
test "std.PriorityQueue: siftUp in remove" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
var queue = PQlt.init(testing.allocator, {});
defer queue.deinit();
@@ -610,6 +623,7 @@ fn contextLessThan(context: []const u32, a: usize, b: usize) Order {
const CPQlt = PriorityQueue(usize, []const u32, contextLessThan);
test "std.PriorityQueue: add and remove min heap with contextful comparator" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const context = [_]u32{ 5, 3, 4, 2, 2, 8, 0 };
var queue = CPQlt.init(testing.allocator, context[0..]);
diff --git a/lib/std/tz.zig b/lib/std/tz.zig
@@ -214,6 +214,7 @@ pub const Tz = struct {
};
test "slim" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const data = @embedFile("tz/asia_tokyo.tzif");
var in_stream = std.io.fixedBufferStream(data);
@@ -227,6 +228,7 @@ test "slim" {
}
test "fat" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
const data = @embedFile("tz/antarctica_davis.tzif");
var in_stream = std.io.fixedBufferStream(data);
@@ -239,6 +241,7 @@ test "fat" {
}
test "legacy" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; // TODO
// Taken from Slackware 8.0, from 2001
const data = @embedFile("tz/europe_vatican.tzif");
var in_stream = std.io.fixedBufferStream(data);
diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig
@@ -804,7 +804,6 @@ pub fn fmtUtf16le(utf16le: []const u16) std.fmt.Formatter(formatUtf16le) {
}
test "fmtUtf16le" {
- if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
const expectFmt = std.testing.expectFmt;
try expectFmt("", "{}", .{fmtUtf16le(utf8ToUtf16LeStringLiteral(""))});
try expectFmt("foo", "{}", .{fmtUtf16le(utf8ToUtf16LeStringLiteral("foo"))});
diff --git a/lib/std/x.zig b/lib/std/x.zig
@@ -13,7 +13,6 @@ pub const net = struct {
};
test {
- if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
inline for (.{ os, net }) |module| {
std.testing.refAllDecls(module);
}
diff --git a/lib/std/x/os/io.zig b/lib/std/x/os/io.zig
@@ -117,6 +117,7 @@ pub const Reactor = struct {
};
test "reactor/linux: drive async tcp client/listener pair" {
+ if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
if (native_os.tag != .linux) return error.SkipZigTest;
const ip = std.x.net.ip;
diff --git a/lib/std/x/os/net.zig b/lib/std/x/os/net.zig
@@ -381,7 +381,7 @@ pub const IPv6 = extern struct {
});
}
- const zero_span = span: {
+ const zero_span: struct { from: usize, to: usize } = span: {
var i: usize = 0;
while (i < self.octets.len) : (i += 2) {
if (self.octets[i] == 0 and self.octets[i + 1] == 0) break;
diff --git a/src/AstGen.zig b/src/AstGen.zig
@@ -2753,7 +2753,10 @@ fn varDecl(
const result_loc: ResultLoc = if (type_node != 0) .{
.ty = try typeExpr(gz, scope, type_node),
} else .none;
+ const prev_anon_name_strategy = gz.anon_name_strategy;
+ gz.anon_name_strategy = .dbg_var;
const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
+ gz.anon_name_strategy = prev_anon_name_strategy;
try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);
@@ -2777,6 +2780,7 @@ fn varDecl(
var init_scope = gz.makeSubBlock(scope);
// we may add more instructions to gz before stacking init_scope
init_scope.instructions_top = GenZir.unstacked_top;
+ init_scope.anon_name_strategy = .dbg_var;
defer init_scope.unstack();
var resolve_inferred_alloc: Zir.Inst.Ref = .none;
@@ -2956,7 +2960,10 @@ fn varDecl(
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
};
+ const prev_anon_name_strategy = gz.anon_name_strategy;
+ gz.anon_name_strategy = .dbg_var;
_ = try reachableExprComptime(gz, scope, var_data.result_loc, var_decl.ast.init_node, node, is_comptime);
+ gz.anon_name_strategy = prev_anon_name_strategy;
if (resolve_inferred_alloc != .none) {
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
diff --git a/src/Module.zig b/src/Module.zig
@@ -3790,9 +3790,12 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
defer liveness.deinit(gpa);
if (builtin.mode == .Debug and mod.comp.verbose_air) {
- std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
+ const fqn = try decl.getFullyQualifiedName(mod);
+ defer mod.gpa.free(fqn);
+
+ std.debug.print("# Begin Function AIR: {s}:\n", .{fqn});
@import("print_air.zig").dump(mod, air, liveness);
- std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
+ std.debug.print("# End Function AIR: {s}\n\n", .{fqn});
}
mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -914,9 +914,9 @@ fn analyzeBodyInner(
// zig fmt: off
.variable => try sema.zirVarExtended( block, extended),
.struct_decl => try sema.zirStructDecl( block, extended, inst),
- .enum_decl => try sema.zirEnumDecl( block, extended),
+ .enum_decl => try sema.zirEnumDecl( block, extended, inst),
.union_decl => try sema.zirUnionDecl( block, extended, inst),
- .opaque_decl => try sema.zirOpaqueDecl( block, extended),
+ .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst),
.this => try sema.zirThis( block, extended),
.ret_addr => try sema.zirRetAddr( block, extended),
.builtin_src => try sema.zirBuiltinSrc( block, extended),
@@ -2101,7 +2101,7 @@ fn zirStructDecl(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = struct_val,
- }, small.name_strategy, "struct");
+ }, small.name_strategy, "struct", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -2133,6 +2133,7 @@ fn createAnonymousDeclTypeNamed(
typed_value: TypedValue,
name_strategy: Zir.Inst.NameStrategy,
anon_prefix: []const u8,
+ inst: ?Zir.Inst.Index,
) !Decl.Index {
const mod = sema.mod;
const namespace = block.namespace;
@@ -2152,11 +2153,13 @@ fn createAnonymousDeclTypeNamed(
const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{
src_decl.name, anon_prefix, @enumToInt(new_decl_index),
});
+ errdefer sema.gpa.free(name);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
.parent => {
const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
+ errdefer sema.gpa.free(name);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
@@ -2188,9 +2191,31 @@ fn createAnonymousDeclTypeNamed(
try buf.appendSlice(")");
const name = try buf.toOwnedSliceSentinel(0);
+ errdefer sema.gpa.free(name);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
+ .dbg_var => {
+ const ref = Zir.indexToRef(inst.?);
+ const zir_tags = sema.code.instructions.items(.tag);
+ const zir_data = sema.code.instructions.items(.data);
+ var i = inst.?;
+ while (i < zir_tags.len) : (i += 1) switch (zir_tags[i]) {
+ .dbg_var_ptr, .dbg_var_val => {
+ if (zir_data[i].str_op.operand != ref) continue;
+
+ const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{
+ src_decl.name, zir_data[i].str_op.getStr(sema.code),
+ });
+ errdefer sema.gpa.free(name);
+
+ try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
+ return new_decl_index;
+ },
+ else => {},
+ };
+ return sema.createAnonymousDeclTypeNamed(block, typed_value, .anon, anon_prefix, null);
+ },
}
}
@@ -2198,6 +2223,7 @@ fn zirEnumDecl(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
+ inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -2252,7 +2278,7 @@ fn zirEnumDecl(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = enum_val,
- }, small.name_strategy, "enum");
+ }, small.name_strategy, "enum", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -2472,7 +2498,7 @@ fn zirUnionDecl(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = union_val,
- }, small.name_strategy, "union");
+ }, small.name_strategy, "union", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -2504,6 +2530,7 @@ fn zirOpaqueDecl(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
+ inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -2540,7 +2567,7 @@ fn zirOpaqueDecl(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = opaque_val,
- }, small.name_strategy, "opaque");
+ }, small.name_strategy, "opaque", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -2589,7 +2616,7 @@ fn zirErrorSetDecl(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = error_set_val,
- }, name_strategy, "error");
+ }, name_strategy, "error", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -4967,6 +4994,8 @@ fn lookupInNamespace(
var it = check_ns.usingnamespace_set.iterator();
while (it.next()) |entry| {
const sub_usingnamespace_decl_index = entry.key_ptr.*;
+ // Skip the decl we're currently analysing.
+ if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue;
const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index);
const sub_is_pub = entry.value_ptr.*;
if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) {
@@ -6180,6 +6209,17 @@ fn zirErrorToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
}
+ const op_ty = sema.typeOf(op);
+ try sema.resolveInferredErrorSetTy(block, src, op_ty);
+ if (!op_ty.isAnyError()) {
+ const names = op_ty.errorSetNames();
+ switch (names.len) {
+ 0 => return sema.addConstant(result_ty, Value.zero),
+ 1 => return sema.addIntUnsigned(result_ty, sema.mod.global_error_set.get(names[0]).?),
+ else => {},
+ }
+ }
+
try sema.requireRuntimeBlock(block, src);
return block.addBitCast(result_ty, op_coerced);
}
@@ -6558,7 +6598,7 @@ fn analyzeErrUnionPayload(
// If the error set has no fields then no safety check is needed.
if (safety_check and block.wantSafety() and
- err_union_ty.errorUnionSet().errorSetCardinality() != .zero)
+ !err_union_ty.errorUnionSet().errorSetIsEmpty())
{
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
}
@@ -6644,7 +6684,7 @@ fn analyzeErrUnionPayloadPtr(
// If the error set has no fields then no safety check is needed.
if (safety_check and block.wantSafety() and
- err_union_ty.errorUnionSet().errorSetCardinality() != .zero)
+ !err_union_ty.errorUnionSet().errorSetIsEmpty())
{
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
}
@@ -11859,10 +11899,14 @@ fn zirBuiltinSrc(
const file_name_val = blk: {
var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
- const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena());
+ const relative_path = try fn_owner_decl.getFileScope().fullPath(sema.arena);
+ const absolute_path = std.fs.realpathAlloc(sema.arena, relative_path) catch |err| {
+ return sema.fail(block, src, "failed to get absolute path of file '{s}': {s}", .{ relative_path, @errorName(err) });
+ };
+ const aboslute_duped = try anon_decl.arena().dupeZ(u8, absolute_path);
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len),
- try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]),
+ try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), aboslute_duped.len),
+ try Value.Tag.bytes.create(anon_decl.arena(), aboslute_duped[0 .. aboslute_duped.len + 1]),
0, // default alignment
);
break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
@@ -11873,6 +11917,7 @@ fn zirBuiltinSrc(
field_values[0] = file_name_val;
// fn_name: [:0]const u8,
field_values[1] = func_name_val;
+ // TODO these should be runtime only!
// line: u32
field_values[2] = try Value.Tag.int_u64.create(sema.arena, extra.line + 1);
// column: u32,
@@ -13712,10 +13757,10 @@ fn zirStructInit(
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
+ const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
const init_inst = try sema.resolveInst(item.data.init);
if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
return sema.addConstantMaybeRef(
block,
src,
@@ -13734,6 +13779,8 @@ fn zirStructInit(
const alloc = try block.addTy(.alloc, alloc_ty);
const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty);
try sema.storePtr(block, src, field_ptr, init_inst);
+ const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
+ _ = try block.addBinOp(.set_union_tag, alloc, new_tag);
return alloc;
}
@@ -14614,7 +14661,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = enum_val,
- }, .anon, "enum");
+ }, .anon, "enum", null);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -14704,7 +14751,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = opaque_val,
- }, .anon, "opaque");
+ }, .anon, "opaque", null);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -14755,7 +14802,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = new_union_val,
- }, .anon, "union");
+ }, .anon, "union", null);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -14923,7 +14970,7 @@ fn reifyStruct(
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
.ty = Type.type,
.val = new_struct_val,
- }, .anon, "struct");
+ }, .anon, "struct", null);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -19700,7 +19747,8 @@ fn coerce(
// pointer to tuple to slice
if (inst_ty.isSinglePointer() and
inst_ty.childType().isTuple() and
- !dest_info.mutable and dest_info.size == .Slice)
+ (!dest_info.mutable or inst_ty.ptrIsMutable() or inst_ty.childType().tupleFields().types.len == 0) and
+ dest_info.size == .Slice)
{
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
}
@@ -23540,7 +23588,17 @@ pub fn resolveTypeFully(
const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
return resolveTypeFully(sema, block, src, child_ty);
},
- .Struct => return resolveStructFully(sema, block, src, ty),
+ .Struct => switch (ty.tag()) {
+ .@"struct" => return resolveStructFully(sema, block, src, ty),
+ .tuple, .anon_struct => {
+ const tuple = ty.tupleFields();
+
+ for (tuple.types) |field_ty| {
+ try sema.resolveTypeFully(block, src, field_ty);
+ }
+ },
+ else => {},
+ },
.Union => return resolveUnionFully(sema, block, src, ty),
.Array => return resolveTypeFully(sema, block, src, ty.childType()),
.Optional => {
@@ -23575,7 +23633,7 @@ fn resolveStructFully(
try resolveStructLayout(sema, block, src, ty);
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
- const payload = resolved_ty.castTag(.@"struct") orelse return;
+ const payload = resolved_ty.castTag(.@"struct").?;
const struct_obj = payload.data;
switch (struct_obj.status) {
@@ -24425,6 +24483,10 @@ pub fn typeHasOnePossibleValue(
.bool,
.type,
.anyerror,
+ .error_set_single,
+ .error_set,
+ .error_set_merged,
+ .error_union,
.fn_noreturn_no_args,
.fn_void_no_args,
.fn_naked_noreturn_no_args,
@@ -24481,46 +24543,6 @@ pub fn typeHasOnePossibleValue(
}
},
- .error_union => {
- const error_ty = ty.errorUnionSet();
- switch (error_ty.errorSetCardinality()) {
- .zero => {
- const payload_ty = ty.errorUnionPayload();
- if (try typeHasOnePossibleValue(sema, block, src, payload_ty)) |payload_val| {
- return try Value.Tag.eu_payload.create(sema.arena, payload_val);
- } else {
- return null;
- }
- },
- .one => {
- if (ty.errorUnionPayload().isNoReturn()) {
- const error_val = (try typeHasOnePossibleValue(sema, block, src, error_ty)).?;
- return error_val;
- } else {
- return null;
- }
- },
- .many => return null,
- }
- },
-
- .error_set_single => {
- const name = ty.castTag(.error_set_single).?.data;
- return try Value.Tag.@"error".create(sema.arena, .{ .name = name });
- },
- .error_set => {
- const err_set_obj = ty.castTag(.error_set).?.data;
- const names = err_set_obj.names.keys();
- if (names.len > 1) return null;
- return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
- },
- .error_set_merged => {
- const name_map = ty.castTag(.error_set_merged).?.data;
- const names = name_map.keys();
- if (names.len > 1) return null;
- return try Value.Tag.@"error".create(sema.arena, .{ .name = names[0] });
- },
-
.@"struct" => {
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const s = resolved_ty.castTag(.@"struct").?.data;
diff --git a/src/TypedValue.zig b/src/TypedValue.zig
@@ -144,7 +144,41 @@ pub fn print(
return writer.writeAll(".{ ... }");
}
const vals = val.castTag(.aggregate).?.data;
- if (ty.zigTypeTag() == .Struct) {
+ if (ty.castTag(.anon_struct)) |anon_struct| {
+ const field_names = anon_struct.data.names;
+ const types = anon_struct.data.types;
+ const max_len = std.math.min(types.len, max_aggregate_items);
+
+ var i: u32 = 0;
+ while (i < max_len) : (i += 1) {
+ if (i != 0) try writer.writeAll(", ");
+ try writer.print(".{s} = ", .{field_names[i]});
+ try print(.{
+ .ty = types[i],
+ .val = vals[i],
+ }, writer, level - 1, mod);
+ }
+ if (types.len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
+ return writer.writeAll(" }");
+ } else if (ty.isTuple()) {
+ const fields = ty.tupleFields();
+ const max_len = std.math.min(fields.types.len, max_aggregate_items);
+
+ var i: u32 = 0;
+ while (i < max_len) : (i += 1) {
+ if (i != 0) try writer.writeAll(", ");
+ try print(.{
+ .ty = fields.types[i],
+ .val = vals[i],
+ }, writer, level - 1, mod);
+ }
+ if (fields.types.len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
+ return writer.writeAll(" }");
+ } else if (ty.zigTypeTag() == .Struct) {
try writer.writeAll(".{ ");
const struct_fields = ty.structFields();
const len = struct_fields.count();
@@ -194,7 +228,7 @@ pub fn print(
try writer.writeAll(".{ ");
try print(.{
- .ty = ty.unionTagType().?,
+ .ty = ty.cast(Type.Payload.Union).?.data.tag_ty,
.val = union_val.tag,
}, writer, level - 1, mod);
try writer.writeAll(" = ");
@@ -278,19 +312,27 @@ pub fn print(
.elem_ptr => {
const elem_ptr = val.castTag(.elem_ptr).?.data;
try writer.writeAll("&");
- try print(.{
- .ty = elem_ptr.elem_ty,
- .val = elem_ptr.array_ptr,
- }, writer, level - 1, mod);
+ if (level == 0) {
+ try writer.writeAll("(ptr)");
+ } else {
+ try print(.{
+ .ty = elem_ptr.elem_ty,
+ .val = elem_ptr.array_ptr,
+ }, writer, level - 1, mod);
+ }
return writer.print("[{}]", .{elem_ptr.index});
},
.field_ptr => {
const field_ptr = val.castTag(.field_ptr).?.data;
try writer.writeAll("&");
- try print(.{
- .ty = field_ptr.container_ty,
- .val = field_ptr.container_ptr,
- }, writer, level - 1, mod);
+ if (level == 0) {
+ try writer.writeAll("(ptr)");
+ } else {
+ try print(.{
+ .ty = field_ptr.container_ty,
+ .val = field_ptr.container_ptr,
+ }, writer, level - 1, mod);
+ }
if (field_ptr.container_ty.zigTypeTag() == .Struct) {
const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index];
@@ -344,6 +386,9 @@ pub fn print(
return writer.writeAll(" }");
},
.slice => {
+ if (level == 0) {
+ return writer.writeAll(".{ ... }");
+ }
const payload = val.castTag(.slice).?.data;
try writer.writeAll(".{ ");
const elem_ty = ty.elemType2();
@@ -372,17 +417,25 @@ pub fn print(
.@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
.eu_payload => {
val = val.castTag(.eu_payload).?.data;
+ ty = ty.errorUnionPayload();
},
.opt_payload => {
val = val.castTag(.opt_payload).?.data;
+ var buf: Type.Payload.ElemType = undefined;
+ ty = ty.optionalChild(&buf);
+ return print(.{ .ty = ty, .val = val }, writer, level, mod);
},
.eu_payload_ptr => {
try writer.writeAll("&");
val = val.castTag(.eu_payload_ptr).?.data.container_ptr;
+ ty = ty.elemType2().errorUnionPayload();
},
.opt_payload_ptr => {
try writer.writeAll("&");
- val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
+ val = val.castTag(.opt_payload).?.data;
+ var buf: Type.Payload.ElemType = undefined;
+ ty = ty.elemType2().optionalChild(&buf);
+ return print(.{ .ty = ty, .val = val }, writer, level, mod);
},
// TODO these should not appear in this function
diff --git a/src/Zir.zig b/src/Zir.zig
@@ -3156,6 +3156,8 @@ pub const Inst = struct {
/// Create an anonymous name for this declaration.
/// Like this: "ParentDeclName_struct_69"
anon,
+ /// Use the name specified in the next `dbg_var_{val,ptr}` instruction.
+ dbg_var,
};
/// Trailing:
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
@@ -2277,7 +2277,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
+ if (err_ty.errorSetIsEmpty()) {
return MCValue{ .immediate = 0 };
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -2311,7 +2311,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
+ if (err_ty.errorSetIsEmpty()) {
return error_union_mcv;
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -3590,7 +3590,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (error_type.errorSetCardinality() == .zero) {
+ if (error_type.errorSetIsEmpty()) {
return MCValue{ .immediate = 0 }; // always false
}
@@ -4687,11 +4687,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const error_type = typed_value.ty.errorUnionSet();
const payload_type = typed_value.ty.errorUnionPayload();
- if (error_type.errorSetCardinality() == .zero) {
- const payload_val = typed_value.val.castTag(.eu_payload).?.data;
- return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
- }
-
const is_pl = typed_value.val.errorUnionIsPayload();
if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
@@ -1773,7 +1773,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
+ if (err_ty.errorSetIsEmpty()) {
return MCValue{ .immediate = 0 };
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -1810,7 +1810,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
+ if (err_ty.errorSetIsEmpty()) {
return error_union_mcv;
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -3922,7 +3922,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
const error_type = ty.errorUnionSet();
const error_int_type = Type.initTag(.u16);
- if (error_type.errorSetCardinality() == .zero) {
+ if (error_type.errorSetIsEmpty()) {
return MCValue{ .immediate = 0 }; // always false
}
@@ -5368,12 +5368,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
.ErrorUnion => {
const error_type = typed_value.ty.errorUnionSet();
const payload_type = typed_value.ty.errorUnionPayload();
-
- if (error_type.errorSetCardinality() == .zero) {
- const payload_val = typed_value.val.castTag(.eu_payload).?.data;
- return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
- }
-
const is_pl = typed_value.val.errorUnionIsPayload();
if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
@@ -1377,11 +1377,7 @@ fn isByRef(ty: Type, target: std.Target) bool {
.Int => return ty.intInfo(target).bits > 64,
.Float => return ty.floatBits(target) > 64,
.ErrorUnion => {
- const err_ty = ty.errorUnionSet();
const pl_ty = ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
- return isByRef(pl_ty, target);
- }
if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
return false;
}
@@ -1817,11 +1813,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
switch (ty.zigTypeTag()) {
.ErrorUnion => {
- const err_ty = ty.errorUnionSet();
const pl_ty = ty.errorUnionPayload();
- if (err_ty.errorSetCardinality() == .zero) {
- return self.store(lhs, rhs, pl_ty, 0);
- }
if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
return self.store(lhs, rhs, Type.anyerror, 0);
}
@@ -2357,10 +2349,6 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
},
.ErrorUnion => {
const error_type = ty.errorUnionSet();
- if (error_type.errorSetCardinality() == .zero) {
- const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
- return self.lowerConstant(pl_val, ty.errorUnionPayload());
- }
const is_pl = val.errorUnionIsPayload();
const err_val = if (!is_pl) val else Value.initTag(.zero);
return self.lowerConstant(err_val, error_type);
@@ -2929,7 +2917,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
const err_union_ty = self.air.typeOf(un_op);
const pl_ty = err_union_ty.errorUnionPayload();
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
switch (opcode) {
.i32_ne => return WValue{ .imm32 = 0 },
.i32_eq => return WValue{ .imm32 = 1 },
@@ -2962,10 +2950,6 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
const payload_ty = err_ty.errorUnionPayload();
- if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return operand;
- }
-
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return WValue{ .none = {} };
const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target));
@@ -2984,7 +2968,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
const err_ty = if (op_is_ptr) op_ty.childType() else op_ty;
const payload_ty = err_ty.errorUnionPayload();
- if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (err_ty.errorUnionSet().errorSetIsEmpty()) {
return WValue{ .imm32 = 0 };
}
@@ -3002,10 +2986,6 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(ty_op.operand);
const err_ty = self.air.typeOfIndex(inst);
- if (err_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return operand;
- }
-
const pl_ty = self.air.typeOf(ty_op.operand);
if (!pl_ty.hasRuntimeBitsIgnoreComptime()) {
return operand;
@@ -4633,29 +4613,27 @@ fn lowerTry(
return self.fail("TODO: lowerTry for pointers", .{});
}
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return err_union;
- }
-
const pl_ty = err_union_ty.errorUnionPayload();
const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime();
- // Block we can jump out of when error is not set
- try self.startBlock(.block, wasm.block_empty);
-
- // check if the error tag is set for the error union.
- try self.emitWValue(err_union);
- if (pl_has_bits) {
- const err_offset = @intCast(u32, errUnionErrorOffset(pl_ty, self.target));
- try self.addMemArg(.i32_load16_u, .{
- .offset = err_union.offset() + err_offset,
- .alignment = Type.anyerror.abiAlignment(self.target),
- });
+ if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) {
+ // Block we can jump out of when error is not set
+ try self.startBlock(.block, wasm.block_empty);
+
+ // check if the error tag is set for the error union.
+ try self.emitWValue(err_union);
+ if (pl_has_bits) {
+ const err_offset = @intCast(u32, errUnionErrorOffset(pl_ty, self.target));
+ try self.addMemArg(.i32_load16_u, .{
+ .offset = err_union.offset() + err_offset,
+ .alignment = Type.anyerror.abiAlignment(self.target),
+ });
+ }
+ try self.addTag(.i32_eqz);
+ try self.addLabel(.br_if, 0); // jump out of block when error is '0'
+ try self.genBody(body);
+ try self.endBlock();
}
- try self.addTag(.i32_eqz);
- try self.addLabel(.br_if, 0); // jump out of block when error is '0'
- try self.genBody(body);
- try self.endBlock();
// if we reach here it means error was not set, and we want the payload
if (!pl_has_bits) {
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
@@ -1806,7 +1806,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
const operand = try self.resolveInst(ty_op.operand);
const result: MCValue = result: {
- if (err_ty.errorSetCardinality() == .zero) {
+ if (err_ty.errorSetIsEmpty()) {
break :result MCValue{ .immediate = 0 };
}
@@ -1857,14 +1857,8 @@ fn genUnwrapErrorUnionPayloadMir(
err_union: MCValue,
) !MCValue {
const payload_ty = err_union_ty.errorUnionPayload();
- const err_ty = err_union_ty.errorUnionSet();
const result: MCValue = result: {
- if (err_ty.errorSetCardinality() == .zero) {
- // TODO check if we can reuse
- break :result err_union;
- }
-
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
break :result MCValue.none;
}
@@ -1991,15 +1985,10 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
}
const error_union_ty = self.air.getRefType(ty_op.ty);
- const error_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
const operand = try self.resolveInst(ty_op.operand);
const result: MCValue = result: {
- if (error_ty.errorSetCardinality() == .zero) {
- break :result operand;
- }
-
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
break :result operand;
}
@@ -4651,7 +4640,7 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV
fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue {
const err_type = ty.errorUnionSet();
- if (err_type.errorSetCardinality() == .zero) {
+ if (err_type.errorSetIsEmpty()) {
return MCValue{ .immediate = 0 }; // always false
}
@@ -6909,12 +6898,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
.ErrorUnion => {
const error_type = typed_value.ty.errorUnionSet();
const payload_type = typed_value.ty.errorUnionPayload();
-
- if (error_type.errorSetCardinality() == .zero) {
- const payload_val = typed_value.val.castTag(.eu_payload).?.data;
- return self.genTypedValue(.{ .ty = payload_type, .val = payload_val });
- }
-
const is_pl = typed_value.val.errorUnionIsPayload();
if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
diff --git a/src/codegen.zig b/src/codegen.zig
@@ -705,15 +705,6 @@ pub fn generateSymbol(
.ErrorUnion => {
const error_ty = typed_value.ty.errorUnionSet();
const payload_ty = typed_value.ty.errorUnionPayload();
-
- if (error_ty.errorSetCardinality() == .zero) {
- const payload_val = typed_value.val.castTag(.eu_payload).?.data;
- return generateSymbol(bin_file, src_loc, .{
- .ty = payload_ty,
- .val = payload_val,
- }, code, debug_output, reloc_info);
- }
-
const is_payload = typed_value.val.errorUnionIsPayload();
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
@@ -752,12 +752,6 @@ pub const DeclGen = struct {
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (error_type.errorSetCardinality() == .zero) {
- // We use the payload directly as the type.
- const payload_val = val.castTag(.eu_payload).?.data;
- return dg.renderValue(writer, payload_type, payload_val, location);
- }
-
if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
@@ -1381,13 +1375,8 @@ pub const DeclGen = struct {
return w.writeAll("uint16_t");
},
.ErrorUnion => {
- const error_ty = t.errorUnionSet();
const payload_ty = t.errorUnionPayload();
- if (error_ty.errorSetCardinality() == .zero) {
- return dg.renderType(w, payload_ty);
- }
-
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return dg.renderType(w, Type.anyerror);
}
@@ -2892,41 +2881,36 @@ fn lowerTry(
operand_is_ptr: bool,
result_ty: Type,
) !CValue {
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- // If the error set has no fields, then the payload and the error
- // union are the same value.
- return err_union;
- }
-
+ const writer = f.object.writer();
const payload_ty = err_union_ty.errorUnionPayload();
const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
- const writer = f.object.writer();
-
- err: {
- if (!payload_has_bits) {
- if (operand_is_ptr) {
- try writer.writeAll("if(*");
- } else {
+ if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) {
+ err: {
+ if (!payload_has_bits) {
+ if (operand_is_ptr) {
+ try writer.writeAll("if(*");
+ } else {
+ try writer.writeAll("if(");
+ }
+ try f.writeCValue(writer, err_union);
+ try writer.writeAll(")");
+ break :err;
+ }
+ if (operand_is_ptr or isByRef(err_union_ty)) {
try writer.writeAll("if(");
+ try f.writeCValue(writer, err_union);
+ try writer.writeAll("->error)");
+ break :err;
}
- try f.writeCValue(writer, err_union);
- try writer.writeAll(")");
- break :err;
- }
- if (operand_is_ptr or isByRef(err_union_ty)) {
try writer.writeAll("if(");
try f.writeCValue(writer, err_union);
- try writer.writeAll("->error)");
- break :err;
+ try writer.writeAll(".error)");
}
- try writer.writeAll("if(");
- try f.writeCValue(writer, err_union);
- try writer.writeAll(".error)");
- }
- try genBody(f, body);
- try f.object.indent_writer.insertNewline();
+ try genBody(f, body);
+ try f.object.indent_writer.insertNewline();
+ }
if (!payload_has_bits) {
if (!operand_is_ptr) {
@@ -3466,7 +3450,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
if (operand_ty.zigTypeTag() == .Pointer) {
const err_union_ty = operand_ty.childType();
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
return CValue{ .bytes = "0" };
}
if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) {
@@ -3478,7 +3462,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(";\n");
return local;
}
- if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (operand_ty.errorUnionSet().errorSetIsEmpty()) {
return CValue{ .bytes = "0" };
}
if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
@@ -3507,10 +3491,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]c
const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
- if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return operand;
- }
-
if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
return CValue.none;
}
@@ -3575,11 +3555,6 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
const error_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
- if (error_ty.errorSetCardinality() == .zero) {
- // TODO: write undefined bytes through the pointer here
- return operand;
- }
-
// First, set the non-error value.
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
try f.writeCValueDeref(writer, operand);
@@ -3623,9 +3598,6 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
const inst_ty = f.air.typeOfIndex(inst);
- if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return operand;
- }
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = { .error = 0, .payload = ");
try f.writeCValue(writer, operand);
@@ -3652,7 +3624,7 @@ fn airIsErr(
try writer.writeAll(" = ");
- if (error_ty.errorSetCardinality() == .zero) {
+ if (error_ty.errorSetIsEmpty()) {
try writer.print("0 {s} 0;\n", .{op_str});
} else {
if (is_ptr) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -599,6 +599,13 @@ pub const Object = struct {
self.llvm_module.dump();
}
+ var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
+ defer arena_allocator.deinit();
+ const arena = arena_allocator.allocator();
+
+ const mod = comp.bin_file.options.module.?;
+ const cache_dir = mod.zig_cache_artifact_directory;
+
if (std.debug.runtime_safety) {
var error_message: [*:0]const u8 = undefined;
// verifyModule always allocs the error_message even if there is no error
@@ -606,17 +613,15 @@ pub const Object = struct {
if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
std.debug.print("\n{s}\n", .{error_message});
+
+ if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path| {
+ _ = self.llvm_module.printModuleToFile(emit_llvm_ir_path, &error_message);
+ }
+
@panic("LLVM module verification failed");
}
}
- var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
- defer arena_allocator.deinit();
- const arena = arena_allocator.allocator();
-
- const mod = comp.bin_file.options.module.?;
- const cache_dir = mod.zig_cache_artifact_directory;
-
var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|
try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?))
else
@@ -1566,22 +1571,6 @@ pub const Object = struct {
},
.ErrorUnion => {
const payload_ty = ty.errorUnionPayload();
- switch (ty.errorUnionSet().errorSetCardinality()) {
- .zero => {
- const payload_di_ty = try o.lowerDebugType(payload_ty, .full);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(payload_di_ty), .{ .mod = o.module });
- return payload_di_ty;
- },
- .one => {
- if (payload_ty.isNoReturn()) {
- const di_type = dib.createBasicType("void", 0, DW.ATE.signed);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
- return di_type;
- }
- },
- .many => {},
- }
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full);
// The recursive call to `lowerDebugType` means we can't use `gop` anymore.
@@ -2549,15 +2538,6 @@ pub const DeclGen = struct {
},
.ErrorUnion => {
const payload_ty = t.errorUnionPayload();
- switch (t.errorUnionSet().errorSetCardinality()) {
- .zero => return dg.lowerType(payload_ty),
- .one => {
- if (payload_ty.isNoReturn()) {
- return dg.context.voidType();
- }
- },
- .many => {},
- }
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return try dg.lowerType(Type.anyerror);
}
@@ -3217,10 +3197,6 @@ pub const DeclGen = struct {
},
.ErrorUnion => {
const payload_type = tv.ty.errorUnionPayload();
- if (tv.ty.errorUnionSet().errorSetCardinality() == .zero) {
- const payload_val = tv.val.castTag(.eu_payload).?.data;
- return dg.lowerValue(.{ .ty = payload_type, .val = payload_val });
- }
const is_pl = tv.val.errorUnionIsPayload();
if (!payload_type.hasRuntimeBitsIgnoreComptime()) {
@@ -4790,40 +4766,37 @@ pub const FuncGen = struct {
}
fn lowerTry(fg: *FuncGen, err_union: *const llvm.Value, body: []const Air.Inst.Index, err_union_ty: Type, operand_is_ptr: bool, result_ty: Type) !?*const llvm.Value {
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- // If the error set has no fields, then the payload and the error
- // union are the same value.
- return err_union;
- }
-
const payload_ty = err_union_ty.errorUnionPayload();
const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
const target = fg.dg.module.getTarget();
- const is_err = err: {
- const err_set_ty = try fg.dg.lowerType(Type.anyerror);
- const zero = err_set_ty.constNull();
- if (!payload_has_bits) {
- const loaded = if (operand_is_ptr) fg.builder.buildLoad(err_union, "") else err_union;
- break :err fg.builder.buildICmp(.NE, loaded, zero, "");
- }
- const err_field_index = errUnionErrorOffset(payload_ty, target);
- if (operand_is_ptr or isByRef(err_union_ty)) {
- const err_field_ptr = fg.builder.buildStructGEP(err_union, err_field_index, "");
- const loaded = fg.builder.buildLoad(err_field_ptr, "");
+
+ if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) {
+ const is_err = err: {
+ const err_set_ty = try fg.dg.lowerType(Type.anyerror);
+ const zero = err_set_ty.constNull();
+ if (!payload_has_bits) {
+ const loaded = if (operand_is_ptr) fg.builder.buildLoad(err_union, "") else err_union;
+ break :err fg.builder.buildICmp(.NE, loaded, zero, "");
+ }
+ const err_field_index = errUnionErrorOffset(payload_ty, target);
+ if (operand_is_ptr or isByRef(err_union_ty)) {
+ const err_field_ptr = fg.builder.buildStructGEP(err_union, err_field_index, "");
+ const loaded = fg.builder.buildLoad(err_field_ptr, "");
+ break :err fg.builder.buildICmp(.NE, loaded, zero, "");
+ }
+ const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
break :err fg.builder.buildICmp(.NE, loaded, zero, "");
- }
- const loaded = fg.builder.buildExtractValue(err_union, err_field_index, "");
- break :err fg.builder.buildICmp(.NE, loaded, zero, "");
- };
+ };
- const return_block = fg.context.appendBasicBlock(fg.llvm_func, "TryRet");
- const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");
- _ = fg.builder.buildCondBr(is_err, return_block, continue_block);
+ const return_block = fg.context.appendBasicBlock(fg.llvm_func, "TryRet");
+ const continue_block = fg.context.appendBasicBlock(fg.llvm_func, "TryCont");
+ _ = fg.builder.buildCondBr(is_err, return_block, continue_block);
- fg.builder.positionBuilderAtEnd(return_block);
- try fg.genBody(body);
+ fg.builder.positionBuilderAtEnd(return_block);
+ try fg.genBody(body);
- fg.builder.positionBuilderAtEnd(continue_block);
+ fg.builder.positionBuilderAtEnd(continue_block);
+ }
if (!payload_has_bits) {
if (!operand_is_ptr) return null;
@@ -5660,7 +5633,7 @@ pub const FuncGen = struct {
const err_set_ty = try self.dg.lowerType(Type.initTag(.anyerror));
const zero = err_set_ty.constNull();
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
const llvm_i1 = self.context.intType(1);
switch (op) {
.EQ => return llvm_i1.constInt(1, .False), // 0 == 0
@@ -5783,13 +5756,6 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
- const operand_ty = self.air.typeOf(ty_op.operand);
- const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
- if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- // If the error set has no fields, then the payload and the error
- // union are the same value.
- return operand;
- }
const result_ty = self.air.typeOfIndex(inst);
const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty;
const target = self.dg.module.getTarget();
@@ -5820,7 +5786,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
- if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ if (err_union_ty.errorUnionSet().errorSetIsEmpty()) {
const err_llvm_ty = try self.dg.lowerType(Type.anyerror);
if (operand_is_ptr) {
return self.builder.buildBitCast(operand, err_llvm_ty.pointerType(0), "");
@@ -5851,10 +5817,6 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const error_union_ty = self.air.typeOf(ty_op.operand).childType();
- if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
- // TODO: write undefined bytes through the pointer here
- return operand;
- }
const payload_ty = error_union_ty.errorUnionPayload();
const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero });
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
@@ -5933,9 +5895,6 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const inst_ty = self.air.typeOfIndex(inst);
const operand = try self.resolveInst(ty_op.operand);
- if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
- return operand;
- }
const payload_ty = self.air.typeOf(ty_op.operand);
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return operand;
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
@@ -390,6 +390,9 @@ pub const Module = opaque {
pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;
extern fn LLVMSetModuleInlineAsm2(M: *const Module, Asm: [*]const u8, Len: usize) void;
+
+ pub const printModuleToFile = LLVMPrintModuleToFile;
+ extern fn LLVMPrintModuleToFile(M: *const Module, Filename: [*:0]const u8, ErrorMessage: *[*:0]const u8) Bool;
};
pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
diff --git a/src/print_air.zig b/src/print_air.zig
@@ -4,6 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
const Module = @import("Module.zig");
const Value = @import("value.zig").Value;
+const Type = @import("type.zig").Type;
const Air = @import("Air.zig");
const Liveness = @import("Liveness.zig");
@@ -304,14 +305,27 @@ const Writer = struct {
// no-op, no argument to write
}
+ fn writeType(w: *Writer, s: anytype, ty: Type) !void {
+ const t = ty.tag();
+ switch (t) {
+ .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),
+ .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),
+ .generic_poison => try s.writeAll("(generic_poison)"),
+ .var_args_param => try s.writeAll("(var_args_param)"),
+ .bound_fn => try s.writeAll("(bound_fn)"),
+ else => try ty.print(s, w.module),
+ }
+ }
+
fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty = w.air.instructions.items(.data)[inst].ty;
- try s.print("{}", .{ty.fmtDebug()});
+ try w.writeType(s, ty);
}
fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_op = w.air.instructions.items(.data)[inst].ty_op;
- try s.print("{}, ", .{w.air.getRefType(ty_op.ty).fmtDebug()});
+ try w.writeType(s, w.air.getRefType(ty_op.ty));
+ try s.writeAll(", ");
try w.writeOperand(s, inst, 0, ty_op.operand);
}
@@ -320,7 +334,8 @@ const Writer = struct {
const extra = w.air.extraData(Air.Block, ty_pl.payload);
const body = w.air.extra[extra.end..][0..extra.data.body_len];
- try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()});
+ try w.writeType(s, w.air.getRefType(ty_pl.ty));
+ try s.writeAll(", {\n");
const old_indent = w.indent;
w.indent += 2;
try w.writeBody(s, body);
@@ -335,7 +350,8 @@ const Writer = struct {
const len = @intCast(usize, vector_ty.arrayLen());
const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]);
- try s.print("{}, [", .{vector_ty.fmtDebug()});
+ try w.writeType(s, vector_ty);
+ try s.writeAll(", [");
for (elements) |elem, i| {
if (i != 0) try s.writeAll(", ");
try w.writeOperand(s, inst, i, elem);
@@ -408,7 +424,8 @@ const Writer = struct {
const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
const elem_ty = w.air.typeOfIndex(inst).childType();
- try s.print("{}, ", .{elem_ty.fmtDebug()});
+ try w.writeType(s, elem_ty);
+ try s.writeAll(", ");
try w.writeOperand(s, inst, 0, pl_op.operand);
try s.writeAll(", ");
try w.writeOperand(s, inst, 1, extra.lhs);
@@ -511,7 +528,9 @@ const Writer = struct {
fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const val = w.air.values[ty_pl.payload];
- try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty).fmtDebug(), val.fmtDebug() });
+ const ty = w.air.getRefType(ty_pl.ty);
+ try w.writeType(s, ty);
+ try s.print(", {}", .{val.fmtValue(ty, w.module)});
}
fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
@@ -523,7 +542,7 @@ const Writer = struct {
var op_index: usize = 0;
const ret_ty = w.air.typeOfIndex(inst);
- try s.print("{}", .{ret_ty.fmtDebug()});
+ try w.writeType(s, ret_ty);
if (is_volatile) {
try s.writeAll(", volatile");
@@ -647,7 +666,10 @@ const Writer = struct {
const body = w.air.extra[extra.end..][0..extra.data.body_len];
try w.writeOperand(s, inst, 0, extra.data.ptr);
- try s.print(", {}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()});
+
+ try s.writeAll(", ");
+ try w.writeType(s, w.air.getRefType(ty_pl.ty));
+ try s.writeAll(", {\n");
const old_indent = w.indent;
w.indent += 2;
try w.writeBody(s, body);
diff --git a/src/type.zig b/src/type.zig
@@ -2366,6 +2366,10 @@ pub const Type = extern union {
.anyopaque,
.@"opaque",
.type_info,
+ .error_set_single,
+ .error_union,
+ .error_set,
+ .error_set_merged,
=> return true,
// These are false because they are comptime-only types.
@@ -2389,20 +2393,8 @@ pub const Type = extern union {
.fn_void_no_args,
.fn_naked_noreturn_no_args,
.fn_ccc_void_no_args,
- .error_set_single,
=> return false,
- .error_set => {
- const err_set_obj = ty.castTag(.error_set).?.data;
- const names = err_set_obj.names.keys();
- return names.len > 1;
- },
- .error_set_merged => {
- const name_map = ty.castTag(.error_set_merged).?.data;
- const names = name_map.keys();
- return names.len > 1;
- },
-
// These types have more than one possible value, so the result is the same as
// asking whether they are comptime-only types.
.anyframe_T,
@@ -2443,25 +2435,6 @@ pub const Type = extern union {
}
},
- .error_union => {
- // This code needs to be kept in sync with the equivalent switch prong
- // in abiSizeAdvanced.
- const data = ty.castTag(.error_union).?.data;
- switch (data.error_set.errorSetCardinality()) {
- .zero => return hasRuntimeBitsAdvanced(data.payload, ignore_comptime_only, sema_kit),
- .one => return !data.payload.isNoReturn(),
- .many => {
- if (ignore_comptime_only) {
- return true;
- } else if (sema_kit) |sk| {
- return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
- } else {
- return !comptimeOnly(ty);
- }
- },
- }
- },
-
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
if (struct_obj.status == .field_types_wip) {
@@ -2926,27 +2899,11 @@ pub const Type = extern union {
.anyerror_void_error_union,
.anyerror,
.error_set_inferred,
+ .error_set_single,
+ .error_set,
+ .error_set_merged,
=> return AbiAlignmentAdvanced{ .scalar = 2 },
- .error_set => {
- const err_set_obj = ty.castTag(.error_set).?.data;
- const names = err_set_obj.names.keys();
- if (names.len <= 1) {
- return AbiAlignmentAdvanced{ .scalar = 0 };
- } else {
- return AbiAlignmentAdvanced{ .scalar = 2 };
- }
- },
- .error_set_merged => {
- const name_map = ty.castTag(.error_set_merged).?.data;
- const names = name_map.keys();
- if (names.len <= 1) {
- return AbiAlignmentAdvanced{ .scalar = 0 };
- } else {
- return AbiAlignmentAdvanced{ .scalar = 2 };
- }
- },
-
.array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat),
// TODO audit this - is there any more complicated logic to determine
@@ -2971,12 +2928,7 @@ pub const Type = extern union {
switch (child_type.zigTypeTag()) {
.Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
- .ErrorSet => switch (child_type.errorSetCardinality()) {
- // `?error{}` is comptime-known to be null.
- .zero => return AbiAlignmentAdvanced{ .scalar = 0 },
- .one => return AbiAlignmentAdvanced{ .scalar = 1 },
- .many => return abiAlignmentAdvanced(Type.anyerror, target, strat),
- },
+ .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, target, strat),
.NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 },
else => {},
}
@@ -2999,15 +2951,6 @@ pub const Type = extern union {
// This code needs to be kept in sync with the equivalent switch prong
// in abiSizeAdvanced.
const data = ty.castTag(.error_union).?.data;
- switch (data.error_set.errorSetCardinality()) {
- .zero => return abiAlignmentAdvanced(data.payload, target, strat),
- .one => {
- if (data.payload.isNoReturn()) {
- return AbiAlignmentAdvanced{ .scalar = 0 };
- }
- },
- .many => {},
- }
const code_align = abiAlignment(Type.anyerror, target);
switch (strat) {
.eager, .sema_kit => {
@@ -3118,7 +3061,6 @@ pub const Type = extern union {
.@"undefined",
.enum_literal,
.type_info,
- .error_set_single,
=> return AbiAlignmentAdvanced{ .scalar = 0 },
.noreturn,
@@ -3237,7 +3179,6 @@ pub const Type = extern union {
.empty_struct_literal,
.empty_struct,
.void,
- .error_set_single,
=> return AbiSizeAdvanced{ .scalar = 0 },
.@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) {
@@ -3396,27 +3337,11 @@ pub const Type = extern union {
.anyerror_void_error_union,
.anyerror,
.error_set_inferred,
+ .error_set,
+ .error_set_merged,
+ .error_set_single,
=> return AbiSizeAdvanced{ .scalar = 2 },
- .error_set => {
- const err_set_obj = ty.castTag(.error_set).?.data;
- const names = err_set_obj.names.keys();
- if (names.len <= 1) {
- return AbiSizeAdvanced{ .scalar = 0 };
- } else {
- return AbiSizeAdvanced{ .scalar = 2 };
- }
- },
- .error_set_merged => {
- const name_map = ty.castTag(.error_set_merged).?.data;
- const names = name_map.keys();
- if (names.len <= 1) {
- return AbiSizeAdvanced{ .scalar = 0 };
- } else {
- return AbiSizeAdvanced{ .scalar = 2 };
- }
- },
-
.i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) },
.u29 => return AbiSizeAdvanced{ .scalar = intAbiSize(29, target) },
.i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) },
@@ -3467,24 +3392,6 @@ pub const Type = extern union {
// This code needs to be kept in sync with the equivalent switch prong
// in abiAlignmentAdvanced.
const data = ty.castTag(.error_union).?.data;
- // Here we need to care whether or not the error set is *empty* or whether
- // it only has *one possible value*. In the former case, it means there
- // cannot possibly be an error, meaning the ABI size is equivalent to the
- // payload ABI size. In the latter case, we need to account for the "tag"
- // because even if both the payload type and the error set type of an
- // error union have no runtime bits, an error union still has
- // 1 bit of data which is whether or not the value is an error.
- // Zig still uses the error code encoding at runtime, even when only 1 bit
- // would suffice. This prevents coercions from needing to branch.
- switch (data.error_set.errorSetCardinality()) {
- .zero => return abiSizeAdvanced(data.payload, target, strat),
- .one => {
- if (data.payload.isNoReturn()) {
- return AbiSizeAdvanced{ .scalar = 0 };
- }
- },
- .many => {},
- }
const code_size = abiSize(Type.anyerror, target);
if (!data.payload.hasRuntimeBits()) {
// Same as anyerror.
@@ -3727,11 +3634,7 @@ pub const Type = extern union {
.error_union => {
const payload = ty.castTag(.error_union).?.data;
- if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) {
- return 0;
- } else if (!payload.error_set.hasRuntimeBits()) {
- return payload.payload.bitSizeAdvanced(target, sema_kit);
- } else if (!payload.payload.hasRuntimeBits()) {
+ if (!payload.payload.hasRuntimeBits()) {
return payload.error_set.bitSizeAdvanced(target, sema_kit);
}
@panic("TODO bitSize error union");
@@ -4351,30 +4254,25 @@ pub const Type = extern union {
};
}
- const ErrorSetCardinality = enum { zero, one, many };
-
- pub fn errorSetCardinality(ty: Type) ErrorSetCardinality {
+ /// Returns false for unresolved inferred error sets.
+ pub fn errorSetIsEmpty(ty: Type) bool {
switch (ty.tag()) {
- .anyerror => return .many,
- .error_set_inferred => return .many,
- .error_set_single => return .one,
+ .anyerror => return false,
+ .error_set_inferred => {
+ const inferred_error_set = ty.castTag(.error_set_inferred).?.data;
+ // Can't know for sure.
+ if (!inferred_error_set.is_resolved) return false;
+ if (inferred_error_set.is_anyerror) return false;
+ return inferred_error_set.errors.count() == 0;
+ },
+ .error_set_single => return false,
.error_set => {
const err_set_obj = ty.castTag(.error_set).?.data;
- const names = err_set_obj.names.keys();
- switch (names.len) {
- 0 => return .zero,
- 1 => return .one,
- else => return .many,
- }
+ return err_set_obj.names.count() == 0;
},
.error_set_merged => {
const name_map = ty.castTag(.error_set_merged).?.data;
- const names = name_map.keys();
- switch (names.len) {
- 0 => return .zero,
- 1 => return .one,
- else => return .many,
- }
+ return name_map.count() == 0;
},
else => unreachable,
}
@@ -4883,6 +4781,10 @@ pub const Type = extern union {
.bool,
.type,
.anyerror,
+ .error_union,
+ .error_set_single,
+ .error_set,
+ .error_set_merged,
.fn_noreturn_no_args,
.fn_void_no_args,
.fn_naked_noreturn_no_args,
@@ -4939,42 +4841,6 @@ pub const Type = extern union {
}
},
- .error_union => {
- const error_ty = ty.errorUnionSet();
- switch (error_ty.errorSetCardinality()) {
- .zero => {
- const payload_ty = ty.errorUnionPayload();
- if (onePossibleValue(payload_ty)) |payload_val| {
- _ = payload_val;
- return Value.initTag(.the_only_possible_value);
- } else {
- return null;
- }
- },
- .one => {
- if (ty.errorUnionPayload().isNoReturn()) {
- const error_val = onePossibleValue(error_ty).?;
- return error_val;
- } else {
- return null;
- }
- },
- .many => return null,
- }
- },
-
- .error_set_single => return Value.initTag(.the_only_possible_value),
- .error_set => {
- const err_set_obj = ty.castTag(.error_set).?.data;
- if (err_set_obj.names.count() > 1) return null;
- return Value.initTag(.the_only_possible_value);
- },
- .error_set_merged => {
- const name_map = ty.castTag(.error_set_merged).?.data;
- if (name_map.count() > 1) return null;
- return Value.initTag(.the_only_possible_value);
- },
-
.@"struct" => {
const s = ty.castTag(.@"struct").?.data;
assert(s.haveFieldTypes());
diff --git a/src/value.zig b/src/value.zig
@@ -1062,6 +1062,7 @@ pub const Value = extern union {
sema_kit: ?Module.WipAnalysis,
) Module.CompileError!BigIntConst {
switch (val.tag()) {
+ .null_value,
.zero,
.bool_false,
.the_only_possible_value, // i0, u0
diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig
@@ -1086,3 +1086,26 @@ test "inline call of function with a switch inside the return statement" {
};
try expect(S.foo(1) == 1);
}
+
+test "namespace lookup ignores decl causing the lookup" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ fn Mixin(comptime T: type) type {
+ return struct {
+ fn foo() void {
+ const set = std.EnumSet(T.E).init(undefined);
+ _ = set;
+ }
+ };
+ }
+
+ const E = enum { a, b };
+ usingnamespace Mixin(@This());
+ };
+ _ = S.foo();
+}
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
@@ -1426,6 +1426,7 @@ test "coerce undefined single-item pointer of array to error union of slice" {
}
test "pointer to empty struct literal to mutable slice" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
var x: []i32 = &.{};
try expect(x.len == 0);
}
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
@@ -453,65 +453,6 @@ test "optional error set is the same size as error set" {
comptime try expect(S.returnsOptErrSet() == null);
}
-test "optional error set with only one error is the same size as bool" {
- if (builtin.zig_backend == .stage1) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
-
- const E = error{only};
- comptime try expect(@sizeOf(?E) == @sizeOf(bool));
- comptime try expect(@alignOf(?E) == @alignOf(bool));
- const S = struct {
- fn gimmeNull() ?E {
- return null;
- }
- fn gimmeErr() ?E {
- return error.only;
- }
- };
- try expect(S.gimmeNull() == null);
- try expect(error.only == S.gimmeErr().?);
- comptime try expect(S.gimmeNull() == null);
- comptime try expect(error.only == S.gimmeErr().?);
-}
-
-test "optional empty error set" {
- if (builtin.zig_backend == .stage1) return error.SkipZigTest;
-
- comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
- comptime try expect(@alignOf(error{}!void) == @alignOf(void));
-
- var x: ?error{} = undefined;
- if (x != null) {
- @compileError("test failed");
- }
-}
-
-test "empty error set plus zero-bit payload" {
- if (builtin.zig_backend == .stage1) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
-
- comptime try expect(@sizeOf(error{}!void) == @sizeOf(void));
- comptime try expect(@alignOf(error{}!void) == @alignOf(void));
-
- var x: error{}!void = undefined;
- if (x) |payload| {
- if (payload != {}) {
- @compileError("test failed");
- }
- } else |_| {
- @compileError("test failed");
- }
- const S = struct {
- fn empty() error{}!void {}
- fn inferred() !void {
- return empty();
- }
- };
- try S.inferred();
-}
-
test "nested catch" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig
@@ -137,43 +137,8 @@ const A_Enum = enum {
fn regular() void {}
-test "fn body decl" {
- if (builtin.zig_backend == .stage1) {
- // stage1 fails to return fully qualified namespaces.
- return error.SkipZigTest;
- }
-
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-
- try B.doTest();
-}
-
const B = struct {
- fn doTest() !void {
- const B_Struct = struct {};
- const B_Union = union {
- unused: u8,
- };
- const B_Enum = enum {
- unused,
- };
-
- try expectEqualStringsIgnoreDigits(
- "behavior.typename.B.doTest__struct_0",
- @typeName(B_Struct),
- );
- try expectEqualStringsIgnoreDigits(
- "behavior.typename.B.doTest__union_0",
- @typeName(B_Union),
- );
- try expectEqualStringsIgnoreDigits(
- "behavior.typename.B.doTest__enum_0",
- @typeName(B_Enum),
- );
- }
+ fn doTest() !void {}
};
test "fn param" {
@@ -246,3 +211,27 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
}
return expectEqualStrings(expected, actual_buf[0..actual_i]);
}
+
+test "local variable" {
+ if (builtin.zig_backend == .stage1) {
+ // stage1 fails to return fully qualified namespaces.
+ return error.SkipZigTest;
+ }
+
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ const Foo = struct { a: u32 };
+ const Bar = union { a: u32 };
+ const Baz = enum { a, b };
+ const Qux = enum { a, b };
+ const Quux = enum { a, b };
+
+ try expectEqualStrings("behavior.typename.test.local variable.Foo", @typeName(Foo));
+ try expectEqualStrings("behavior.typename.test.local variable.Bar", @typeName(Bar));
+ try expectEqualStrings("behavior.typename.test.local variable.Baz", @typeName(Baz));
+ try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
+ try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
+}
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
@@ -1183,3 +1183,21 @@ test "comptime equality of extern unions with same tag" {
const b = S.U{ .a = 1234 };
try expect(S.foo(a) == S.foo(b));
}
+
+test "union tag is set when initiated as a temporary value at runtime" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+
+ const U = union(enum) {
+ a,
+ b: u32,
+ c,
+
+ fn doTheTest(u: @This()) !void {
+ try expect(u == .b);
+ }
+ };
+ var b: u32 = 1;
+ try (U{ .b = b }).doTheTest();
+}