| author | |
| committer | |
| log | 99b90a431538de898ad2d49fb719f64572d849ab |
| tree | 719c3b59eac4d6adea5c711ee2bef0dd7c58183a |
| parent | 9c7759bdc3cc6e44ef5ab1c5ce58d310659177df |
4 files changed, 163 insertions(+), 12 deletions(-)
lib/std/zig/AstGen.zig+15-12| ... | @@ -5001,6 +5001,10 @@ fn structDeclInner( | ... | @@ -5001,6 +5001,10 @@ fn structDeclInner( |
| 5001 | ); | 5001 | ); |
| 5002 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); | 5002 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); |
| 5003 | 5003 | ||
| 5004 | const old_hasher = astgen.src_hasher; | ||
| 5005 | defer astgen.src_hasher = old_hasher; | ||
| 5006 | astgen.src_hasher = .init(.{}); | ||
| 5007 | |||
| 5004 | // Before any field bodies comes the backing int type, if specified. | 5008 | // Before any field bodies comes the backing int type, if specified. |
| 5005 | const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: { | 5009 | const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: { |
| 5006 | if (layout != .@"packed") return astgen.failNode( | 5010 | if (layout != .@"packed") return astgen.failNode( |
| ... | @@ -5008,6 +5012,7 @@ fn structDeclInner( | ... | @@ -5008,6 +5012,7 @@ fn structDeclInner( |
| 5008 | "non-packed struct does not support backing integer type", | 5012 | "non-packed struct does not support backing integer type", |
| 5009 | .{}, | 5013 | .{}, |
| 5010 | ); | 5014 | ); |
| 5015 | astgen.src_hasher.update(astgen.tree.getNodeSource(backing_int_node)); | ||
| 5011 | const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node); | 5016 | const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node); |
| 5012 | if (!block_scope.endsWithNoReturn()) { | 5017 | if (!block_scope.endsWithNoReturn()) { |
| 5013 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); | 5018 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); |
| ... | @@ -5017,10 +5022,6 @@ fn structDeclInner( | ... | @@ -5017,10 +5022,6 @@ fn structDeclInner( |
| 5017 | break :len body_len; | 5022 | break :len body_len; |
| 5018 | } else null; | 5023 | } else null; |
| 5019 | 5024 | ||
| 5020 | const old_hasher = astgen.src_hasher; | ||
| 5021 | defer astgen.src_hasher = old_hasher; | ||
| 5022 | astgen.src_hasher = .init(.{}); | ||
| 5023 | |||
| 5024 | var next_field_idx: u32 = 0; | 5025 | var next_field_idx: u32 = 0; |
| 5025 | for (container_decl.ast.members) |member_node| { | 5026 | for (container_decl.ast.members) |member_node| { |
| 5026 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { | 5027 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { |
| ... | @@ -5281,8 +5282,13 @@ fn unionDeclInner( | ... | @@ -5281,8 +5282,13 @@ fn unionDeclInner( |
| 5281 | const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); | 5282 | const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len); |
| 5282 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); | 5283 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); |
| 5283 | 5284 | ||
| 5285 | const old_hasher = astgen.src_hasher; | ||
| 5286 | defer astgen.src_hasher = old_hasher; | ||
| 5287 | astgen.src_hasher = .init(.{}); | ||
| 5288 | |||
| 5284 | // Before any field bodies comes the tag/backing type, if specified. | 5289 | // Before any field bodies comes the tag/backing type, if specified. |
| 5285 | const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: { | 5290 | const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: { |
| 5291 | astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node)); | ||
| 5286 | const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node); | 5292 | const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node); |
| 5287 | if (!block_scope.endsWithNoReturn()) { | 5293 | if (!block_scope.endsWithNoReturn()) { |
| 5288 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); | 5294 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); |
| ... | @@ -5292,10 +5298,6 @@ fn unionDeclInner( | ... | @@ -5292,10 +5298,6 @@ fn unionDeclInner( |
| 5292 | break :len body_len; | 5298 | break :len body_len; |
| 5293 | } else null; | 5299 | } else null; |
| 5294 | 5300 | ||
| 5295 | const old_hasher = astgen.src_hasher; | ||
| 5296 | defer astgen.src_hasher = old_hasher; | ||
| 5297 | astgen.src_hasher = .init(.{}); | ||
| 5298 | |||
| 5299 | var next_field_idx: u32 = 0; | 5301 | var next_field_idx: u32 = 0; |
| 5300 | for (members) |member_node| { | 5302 | for (members) |member_node| { |
| 5301 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { | 5303 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) { |
| ... | @@ -5486,8 +5488,13 @@ fn containerDecl( | ... | @@ -5486,8 +5488,13 @@ fn containerDecl( |
| 5486 | const field_names = try scratch.addSlice(fields_len); | 5488 | const field_names = try scratch.addSlice(fields_len); |
| 5487 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); | 5489 | const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len); |
| 5488 | 5490 | ||
| 5491 | const old_hasher = astgen.src_hasher; | ||
| 5492 | defer astgen.src_hasher = old_hasher; | ||
| 5493 | astgen.src_hasher = .init(.{}); | ||
| 5494 | |||
| 5489 | // Before any field bodies comes the tag type, if specified. | 5495 | // Before any field bodies comes the tag type, if specified. |
| 5490 | const tag_type_body_len: ?u32 = if (container_decl.ast.arg.unwrap()) |tag_type_node| len: { | 5496 | const tag_type_body_len: ?u32 = if (container_decl.ast.arg.unwrap()) |tag_type_node| len: { |
| 5497 | astgen.src_hasher.update(astgen.tree.getNodeSource(tag_type_node)); | ||
| 5491 | const type_ref = try typeExpr(&block_scope, &namespace.base, tag_type_node); | 5498 | const type_ref = try typeExpr(&block_scope, &namespace.base, tag_type_node); |
| 5492 | if (!block_scope.endsWithNoReturn()) { | 5499 | if (!block_scope.endsWithNoReturn()) { |
| 5493 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); | 5500 | _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref); |
| ... | @@ -5497,10 +5504,6 @@ fn containerDecl( | ... | @@ -5497,10 +5504,6 @@ fn containerDecl( |
| 5497 | break :len body_len; | 5504 | break :len body_len; |
| 5498 | } else null; | 5505 | } else null; |
| 5499 | 5506 | ||
| 5500 | const old_hasher = astgen.src_hasher; | ||
| 5501 | defer astgen.src_hasher = old_hasher; | ||
| 5502 | astgen.src_hasher = .init(.{}); | ||
| 5503 | |||
| 5504 | var next_field_idx: u32 = 0; | 5507 | var next_field_idx: u32 = 0; |
| 5505 | var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none; | 5508 | var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none; |
| 5506 | for (container_decl.ast.members) |member_node| { | 5509 | for (container_decl.ast.members) |member_node| { |
test/incremental/change_bitpack_backing_int created+77| ... | @@ -0,0 +1,77 @@ | ||
| 1 | #update=initial version | ||
| 2 | #file=main.zig | ||
| 3 | const Foo = packed struct(u8) { a: u4, b: i4 }; | ||
| 4 | const Bar = packed union(u10) { a: u10, b: i10 }; | ||
| 5 | pub fn main() void {} | ||
| 6 | comptime { | ||
| 7 | @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); | ||
| 8 | } | ||
| 9 | comptime { | ||
| 10 | @compileLog(@bitSizeOf(Bar)); | ||
| 11 | } | ||
| 12 | const std = @import("std"); | ||
| 13 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 14 | #expect_error=main.zig:5:5: error: found compile log statement | ||
| 15 | #expect_error=main.zig:8:5: note: also here | ||
| 16 | #expect_compile_log=@as(type, u8) | ||
| 17 | #expect_compile_log=@as(comptime_int, 10) | ||
| 18 | |||
| 19 | #update=make backing types signed | ||
| 20 | #file=main.zig | ||
| 21 | const Foo = packed struct(i8) { a: u4, b: i4 }; | ||
| 22 | const Bar = packed union(i10) { a: u10, b: i10 }; | ||
| 23 | pub fn main() void {} | ||
| 24 | comptime { | ||
| 25 | @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); | ||
| 26 | } | ||
| 27 | comptime { | ||
| 28 | @compileLog(@bitSizeOf(Bar)); | ||
| 29 | } | ||
| 30 | const std = @import("std"); | ||
| 31 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 32 | #expect_error=main.zig:5:5: error: found compile log statement | ||
| 33 | #expect_error=main.zig:8:5: note: also here | ||
| 34 | #expect_compile_log=@as(type, i8) | ||
| 35 | #expect_compile_log=@as(comptime_int, 10) | ||
| 36 | |||
| 37 | #update=make backing types too small | ||
| 38 | #file=main.zig | ||
| 39 | const Foo = packed struct(i5) { a: u4, b: i4 }; | ||
| 40 | const Bar = packed union(i8) { a: u10, b: i10 }; | ||
| 41 | pub fn main() void {} | ||
| 42 | comptime { | ||
| 43 | @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); | ||
| 44 | } | ||
| 45 | comptime { | ||
| 46 | @compileLog(@bitSizeOf(Bar)); | ||
| 47 | } | ||
| 48 | const std = @import("std"); | ||
| 49 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 50 | #expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields | ||
| 51 | #expect_error=main.zig:1:27: note: backing integer 'i5' has bit width '5' | ||
| 52 | #expect_error=main.zig:1:20: note: struct fields have total bit width '8' | ||
| 53 | #expect_error=main.zig:2:35: error: field bit width does not match backing integer | ||
| 54 | #expect_error=main.zig:2:35: note: field type 'u10' has bit width '10' | ||
| 55 | #expect_error=main.zig:2:26: note: backing integer 'i8' has bit width '8' | ||
| 56 | #expect_error=main.zig:2:35: note: all fields in a packed union must have the same bit width | ||
| 57 | |||
| 58 | #update=make backing types too big | ||
| 59 | #file=main.zig | ||
| 60 | const Foo = packed struct(u10) { a: u4, b: i4 }; | ||
| 61 | const Bar = packed union(u32) { a: u10, b: i10 }; | ||
| 62 | pub fn main() void {} | ||
| 63 | comptime { | ||
| 64 | @compileLog(@typeInfo(Foo).@"struct".backing_integer.?); | ||
| 65 | } | ||
| 66 | comptime { | ||
| 67 | @compileLog(@bitSizeOf(Bar)); | ||
| 68 | } | ||
| 69 | const std = @import("std"); | ||
| 70 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 71 | #expect_error=main.zig:1:20: error: backing integer bit width does not match total bit width of fields | ||
| 72 | #expect_error=main.zig:1:27: note: backing integer 'u10' has bit width '10' | ||
| 73 | #expect_error=main.zig:1:20: note: struct fields have total bit width '8' | ||
| 74 | #expect_error=main.zig:2:36: error: field bit width does not match backing integer | ||
| 75 | #expect_error=main.zig:2:36: note: field type 'u10' has bit width '10' | ||
| 76 | #expect_error=main.zig:2:26: note: backing integer 'u32' has bit width '32' | ||
| 77 | #expect_error=main.zig:2:36: note: all fields in a packed union must have the same bit width | ||
test/incremental/change_enum_tag_type+32| ... | @@ -59,3 +59,35 @@ pub fn main() !void { | ... | @@ -59,3 +59,35 @@ pub fn main() !void { |
| 59 | const std = @import("std"); | 59 | const std = @import("std"); |
| 60 | const io = std.Io.Threaded.global_single_threaded.io(); | 60 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 61 | #expect_stdout="a\n" | 61 | #expect_stdout="a\n" |
| 62 | #update=specify tag directly | ||
| 63 | #file=main.zig | ||
| 64 | const Foo = enum(u3) { | ||
| 65 | a, | ||
| 66 | b, | ||
| 67 | c, | ||
| 68 | d, | ||
| 69 | e, | ||
| 70 | }; | ||
| 71 | pub fn main() !void { | ||
| 72 | @compileLog(@typeInfo(Foo).@"enum".tag_type); | ||
| 73 | } | ||
| 74 | const std = @import("std"); | ||
| 75 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 76 | #expect_error=main.zig:9:5: error: found compile log statement | ||
| 77 | #expect_compile_log=@as(type, u3) | ||
| 78 | #update=change directly-specified tag type | ||
| 79 | #file=main.zig | ||
| 80 | const Foo = enum(u8) { | ||
| 81 | a, | ||
| 82 | b, | ||
| 83 | c, | ||
| 84 | d, | ||
| 85 | e, | ||
| 86 | }; | ||
| 87 | pub fn main() !void { | ||
| 88 | @compileLog(@typeInfo(Foo).@"enum".tag_type); | ||
| 89 | } | ||
| 90 | const std = @import("std"); | ||
| 91 | const io = std.Io.Threaded.global_single_threaded.io(); | ||
| 92 | #expect_error=main.zig:9:5: error: found compile log statement | ||
| 93 | #expect_compile_log=@as(type, u8) |
test/incremental/change_union_tag_type created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | #update=initial version | ||
| 2 | #file=main.zig | ||
| 3 | const A = enum(u8) { a }; | ||
| 4 | const B = enum(u8) { b }; | ||
| 5 | const Foo = union(A) { a: u8 }; | ||
| 6 | pub fn main(init: std.process.Init) !void { | ||
| 7 | const field_name = @typeInfo(Foo).@"union".fields[0].name; | ||
| 8 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 9 | try stdout_writer.interface.print("{s}\n", .{field_name}); | ||
| 10 | } | ||
| 11 | const std = @import("std"); | ||
| 12 | #expect_stdout="a\n" | ||
| 13 | |||
| 14 | #update=change tag type | ||
| 15 | #file=main.zig | ||
| 16 | const A = enum(u8) { a }; | ||
| 17 | const B = enum(u8) { b }; | ||
| 18 | const Foo = union(B) { a: u8 }; | ||
| 19 | pub fn main(init: std.process.Init) !void { | ||
| 20 | const field_name = @typeInfo(Foo).@"union".fields[0].name; | ||
| 21 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 22 | try stdout_writer.interface.print("{s}\n", .{field_name}); | ||
| 23 | } | ||
| 24 | const std = @import("std"); | ||
| 25 | #expect_error=main.zig:3:24: error: no field named 'a' in enum 'main.B' | ||
| 26 | #expect_error=main.zig:2:11: note: enum declared here | ||
| 27 | |||
| 28 | #update=change field name to match new tag type | ||
| 29 | #file=main.zig | ||
| 30 | const A = enum(u8) { a }; | ||
| 31 | const B = enum(u8) { b }; | ||
| 32 | const Foo = union(B) { b: u8 }; | ||
| 33 | pub fn main(init: std.process.Init) !void { | ||
| 34 | const field_name = @typeInfo(Foo).@"union".fields[0].name; | ||
| 35 | var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); | ||
| 36 | try stdout_writer.interface.print("{s}\n", .{field_name}); | ||
| 37 | } | ||
| 38 | const std = @import("std"); | ||
| 39 | #expect_stdout="b\n" | ||