diff --git a/ci/zinc/linux_test.sh b/ci/zinc/linux_test.sh index 1c82992b25..0bb176d4ad 100755 --- 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 index 8006a623b5..9b0079ec74 100644 --- 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 index 1d671f1aa6..7fa25175d5 100644 --- 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 index 58b1955838..50836f2b9a 100644 --- 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 index b35857c731..4f8efd0d6e 100644 --- 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 index 937af90d98..a906bb1037 100644 --- 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 index 6a8e9fa421..b3a255e598 100644 --- 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 index 7269470d5f..16c20a4a78 100644 --- 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 index d7a0e0fb80..d5e9fddaf1 100644 --- 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 index 56fa76b5c0..40074b2c6e 100644 --- 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 index e8cb6bab7b..11441df161 100644 --- 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 index 9afb556b5a..449cc6a919 100644 --- 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 index 2345a97855..ce5256028c 100644 --- 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 index b5fd6d4d9a..521724a998 100644 --- 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 index 9aab487d37..cb19212b5b 100644 --- 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 index 61d6b84874..7c8e914b57 100644 --- 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 index 51671bca78..1a52fda5be 100644 --- 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 index 9d733efdfd..cea845e148 100644 --- 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 index a0cf7f6624..81a7ed838f 100644 --- 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 index bafcdd5426..64caf324ed 100644 --- 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 index 35e7c3e1ed..e61d212e52 100644 --- 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 index d4a17f8679..a7cc8fbc4a 100644 --- 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 index 3f22146f0e..078523831c 100644 --- 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 index f03ba77a39..bcf6491ce6 100644 --- 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 index bad343f941..a5e991c617 100644 --- 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 index 4b3bc23231..3c1b28e544 100644 --- 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 index 1ca31755f7..b43b775dfa 100644 --- 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 index 7a7ee31117..e74fbd44ac 100644 --- 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 index 2bf57943c3..3cc853154b 100644 --- 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 index a0bb84a9d7..c395c26437 100644 --- 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); + 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), - }); + // 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 index 5bda84c98c..c94eaa37af 100644 --- 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 index 84615d86d8..025decdb4b 100644 --- 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 index 45191f3107..949e2a67f2 100644 --- 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 { - try writer.writeAll("if("); + 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 index 19a6917be4..efe6a754b6 100644 --- 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; + + 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 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 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 index ca748d3ce3..671014ba3b 100644 --- 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 index af1bcb8cfb..d6db7ca75f 100644 --- 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 index 8556526e18..0ca7ba83c5 100644 --- 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 index e1500fe4ab..996aa76bf5 100644 --- 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 index a69df862c1..ac9d90d5e6 100644 --- 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 index 4ff2c78d47..383b72e046 100644 --- 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 index ac51ec1eae..c9697a0f82 100644 --- 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 index b237779886..e0cb5ba68c 100644 --- 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 index 4daa9c1ee5..caa5d26aea 100644 --- 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(); +}