diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index b2a72d23b8..5468028ae9 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -5001,6 +5001,10 @@ fn structDeclInner( ); if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); + const old_hasher = astgen.src_hasher; + defer astgen.src_hasher = old_hasher; + astgen.src_hasher = .init(.{}); + // Before any field bodies comes the backing int type, if specified. const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: { if (layout != .@"packed") return astgen.failNode( @@ -5008,6 +5012,7 @@ fn structDeclInner( "non-packed struct does not support backing integer type", .{}, ); + astgen.src_hasher.update(astgen.tree.getNodeSource(backing_int_node)); const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node); if (!block_scope.endsWithNoReturn()) { _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); @@ -5017,10 +5022,6 @@ fn structDeclInner( break :len body_len; } else null; - const old_hasher = astgen.src_hasher; - defer astgen.src_hasher = old_hasher; - astgen.src_hasher = .init(.{}); - var next_field_idx: u32 = 0; for (container_decl.ast.members) |member_node| { var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { @@ -5281,8 +5282,13 @@ fn unionDeclInner( const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); + const old_hasher = astgen.src_hasher; + defer astgen.src_hasher = old_hasher; + astgen.src_hasher = .init(.{}); + // Before any field bodies comes the tag/backing type, if specified. const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: { + astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node)); const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node); if (!block_scope.endsWithNoReturn()) { _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); @@ -5292,10 +5298,6 @@ fn unionDeclInner( break :len body_len; } else null; - const old_hasher = astgen.src_hasher; - defer astgen.src_hasher = old_hasher; - astgen.src_hasher = .init(.{}); - var next_field_idx: u32 = 0; for (members) |member_node| { var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { @@ -5486,8 +5488,13 @@ fn containerDecl( const field_names = try scratch.addSlice(fields_len); const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); + const old_hasher = astgen.src_hasher; + defer astgen.src_hasher = old_hasher; + astgen.src_hasher = .init(.{}); + // Before any field bodies comes the tag type, if specified. const tag_type_body_len: ?u32 = if (container_decl.ast.arg.unwrap()) |tag_type_node| len: { + astgen.src_hasher.update(astgen.tree.getNodeSource(tag_type_node)); const type_ref = try typeExpr(&block_scope, &namespace.base, tag_type_node); if (!block_scope.endsWithNoReturn()) { _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); @@ -5497,10 +5504,6 @@ fn containerDecl( break :len body_len; } else null; - const old_hasher = astgen.src_hasher; - defer astgen.src_hasher = old_hasher; - astgen.src_hasher = .init(.{}); - var next_field_idx: u32 = 0; var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none; for (container_decl.ast.members) |member_node| { diff --git a/test/incremental/change_bitpack_backing_int b/test/incremental/change_bitpack_backing_int new file mode 100644 index 0000000000..0af16aa43e --- /dev/null +++ b/test/incremental/change_bitpack_backing_int @@ -0,0 +1,77 @@ +#update=initial version +#file=main.zig +const Foo = packed struct(u8) { a: u4, b: i4 }; +const Bar = packed union(u10) { a: u10, b: i10 }; +pub fn main() void {} +comptime { + @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); +} +comptime { + @compileLog(@bitSizeOf(Bar)); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:5:5: error: found compile log statement +#expect_error=main.zig:8:5: note: also here +#expect_compile_log=@as(type, u8) +#expect_compile_log=@as(comptime_int, 10) + +#update=make backing types signed +#file=main.zig +const Foo = packed struct(i8) { a: u4, b: i4 }; +const Bar = packed union(i10) { a: u10, b: i10 }; +pub fn main() void {} +comptime { + @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); +} +comptime { + @compileLog(@bitSizeOf(Bar)); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:5:5: error: found compile log statement +#expect_error=main.zig:8:5: note: also here +#expect_compile_log=@as(type, i8) +#expect_compile_log=@as(comptime_int, 10) + +#update=make backing types too small +#file=main.zig +const Foo = packed struct(i5) { a: u4, b: i4 }; +const Bar = packed union(i8) { a: u10, b: i10 }; +pub fn main() void {} +comptime { + @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); +} +comptime { + @compileLog(@bitSizeOf(Bar)); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields +#expect_error=main.zig:1:27: note: backing integer 'i5' has bit width '5' +#expect_error=main.zig:1:20: note: struct fields have total bit width '8' +#expect_error=main.zig:2:35: error: field bit width does not match backing integer +#expect_error=main.zig:2:35: note: field type 'u10' has bit width '10' +#expect_error=main.zig:2:26: note: backing integer 'i8' has bit width '8' +#expect_error=main.zig:2:35: note: all fields in a packed union must have the same bit width + +#update=make backing types too big +#file=main.zig +const Foo = packed struct(u10) { a: u4, b: i4 }; +const Bar = packed union(u32) { a: u10, b: i10 }; +pub fn main() void {} +comptime { + @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); +} +comptime { + @compileLog(@bitSizeOf(Bar)); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields +#expect_error=main.zig:1:27: note: backing integer 'u10' has bit width '10' +#expect_error=main.zig:1:20: note: struct fields have total bit width '8' +#expect_error=main.zig:2:36: error: field bit width does not match backing integer +#expect_error=main.zig:2:36: note: field type 'u10' has bit width '10' +#expect_error=main.zig:2:26: note: backing integer 'u32' has bit width '32' +#expect_error=main.zig:2:36: note: all fields in a packed union must have the same bit width diff --git a/test/incremental/change_enum_tag_type b/test/incremental/change_enum_tag_type index 3e1d184fc8..6ff8a1424d 100644 --- a/test/incremental/change_enum_tag_type +++ b/test/incremental/change_enum_tag_type @@ -59,3 +59,35 @@ pub fn main() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #expect_stdout="a\n" +#update=specify tag directly +#file=main.zig +const Foo = enum(u3) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + @compileLog(@typeInfo(Foo).@"enum".tag_type); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:9:5: error: found compile log statement +#expect_compile_log=@as(type, u3) +#update=change directly-specified tag type +#file=main.zig +const Foo = enum(u8) { + a, + b, + c, + d, + e, +}; +pub fn main() !void { + @compileLog(@typeInfo(Foo).@"enum".tag_type); +} +const std = @import("std"); +const io = std.Io.Threaded.global_single_threaded.io(); +#expect_error=main.zig:9:5: error: found compile log statement +#expect_compile_log=@as(type, u8) diff --git a/test/incremental/change_union_tag_type b/test/incremental/change_union_tag_type new file mode 100644 index 0000000000..2e6fbf3154 --- /dev/null +++ b/test/incremental/change_union_tag_type @@ -0,0 +1,39 @@ +#update=initial version +#file=main.zig +const A = enum(u8) { a }; +const B = enum(u8) { b }; +const Foo = union(A) { a: u8 }; +pub fn main(init: std.process.Init) !void { + const field_name = @typeInfo(Foo).@"union".fields[0].name; + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + try stdout_writer.interface.print("{s}\n", .{field_name}); +} +const std = @import("std"); +#expect_stdout="a\n" + +#update=change tag type +#file=main.zig +const A = enum(u8) { a }; +const B = enum(u8) { b }; +const Foo = union(B) { a: u8 }; +pub fn main(init: std.process.Init) !void { + const field_name = @typeInfo(Foo).@"union".fields[0].name; + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + try stdout_writer.interface.print("{s}\n", .{field_name}); +} +const std = @import("std"); +#expect_error=main.zig:3:24: error: no field named 'a' in enum 'main.B' +#expect_error=main.zig:2:11: note: enum declared here + +#update=change field name to match new tag type +#file=main.zig +const A = enum(u8) { a }; +const B = enum(u8) { b }; +const Foo = union(B) { b: u8 }; +pub fn main(init: std.process.Init) !void { + const field_name = @typeInfo(Foo).@"union".fields[0].name; + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + try stdout_writer.interface.print("{s}\n", .{field_name}); +} +const std = @import("std"); +#expect_stdout="b\n"