authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-19 00:16:26+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-01-19 00:16:26+00:00
logebf782e9444fc97eaecc851a2c9e76ca56d639a7
tree069112ab9e9821a19109bc16b1acd63d6e210fe0
parenta5d2aaa936dc74b85d7cf6695e6a7627d7a645d2
parent3b6e5ba4909b7db68bfde7f19bb23a3b9431649b
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22531 from mlugg/various-fixes

incremental, Sema: minor fixes

4 files changed, 177 insertions(+), 28 deletions(-)

src/Sema.zig+91-22
......@@ -3190,6 +3190,15 @@ fn zirEnumDecl(
31903190
31913191 try sema.declareDependency(.{ .interned = new_ty });
31923192 try sema.addTypeReferenceEntry(src, new_ty);
3193
3194 // Since this is an enum, it has to be resolved immediately.
3195 // `ensureTypeUpToDate` has resolved the new type if necessary.
3196 // We just need to check for resolution failures.
3197 const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
3198 if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
3199 return error.AnalysisFail;
3200 }
3201
31933202 return Air.internedToRef(new_ty);
31943203 },
31953204 .wip => |wip| wip,
......@@ -17801,12 +17810,23 @@ fn zirThis(
1780117810) CompileError!Air.Inst.Ref {
1780217811 _ = extended;
1780317812 const pt = sema.pt;
17813 const zcu = pt.zcu;
1780417814 const namespace = pt.zcu.namespacePtr(block.namespace);
1780517815
1780617816 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
1780717817
1780817818 switch (pt.zcu.intern_pool.indexToKey(new_ty)) {
17809 .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }),
17819 .struct_type, .union_type => try sema.declareDependency(.{ .interned = new_ty }),
17820 .enum_type => {
17821 try sema.declareDependency(.{ .interned = new_ty });
17822 // Since this is an enum, it has to be resolved immediately.
17823 // `ensureTypeUpToDate` has resolved the new type if necessary.
17824 // We just need to check for resolution failures.
17825 const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
17826 if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
17827 return error.AnalysisFail;
17828 }
17829 },
1781017830 .opaque_type => {},
1781117831 else => unreachable,
1781217832 }
......@@ -28478,6 +28498,10 @@ fn unionFieldPtr(
2847828498 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
2847928499 switch (union_obj.flagsUnordered(ip).layout) {
2848028500 .auto => if (initializing) {
28501 if (!sema.isComptimeMutablePtr(union_ptr_val)) {
28502 // The initialization is a runtime operation.
28503 break :ct;
28504 }
2848128505 // Store to the union to initialize the tag.
2848228506 const field_tag = try pt.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
2848328507 const payload_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
......@@ -38330,22 +38354,16 @@ pub fn resolveDeclaredEnum(
3833038354 fields_len: u32,
3833138355 zir: Zir,
3833238356 body_end: usize,
38333) Zcu.CompileError!void {
38357) Zcu.SemaError!void {
3833438358 const zcu = pt.zcu;
3833538359 const gpa = zcu.gpa;
38336 const ip = &zcu.intern_pool;
38337
38338 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
3833938360
3834038361 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };
38341 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
3834238362
38343 const anal_unit = AnalUnit.wrap(.{ .type = wip_ty.index });
38344
38345 var arena = std.heap.ArenaAllocator.init(gpa);
38363 var arena: std.heap.ArenaAllocator = .init(gpa);
3834638364 defer arena.deinit();
3834738365
38348 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
38366 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
3834938367 defer comptime_err_ret_trace.deinit();
3835038368
3835138369 var sema: Sema = .{
......@@ -38353,7 +38371,7 @@ pub fn resolveDeclaredEnum(
3835338371 .gpa = gpa,
3835438372 .arena = arena.allocator(),
3835538373 .code = zir,
38356 .owner = anal_unit,
38374 .owner = .wrap(.{ .type = wip_ty.index }),
3835738375 .func_index = .none,
3835838376 .func_is_naked = false,
3835938377 .fn_ret_ty = Type.void,
......@@ -38379,15 +38397,66 @@ pub fn resolveDeclaredEnum(
3837938397 };
3838038398 defer block.instructions.deinit(gpa);
3838138399
38400 sema.resolveDeclaredEnumInner(
38401 &block,
38402 wip_ty,
38403 inst,
38404 tracked_inst,
38405 src,
38406 small,
38407 body,
38408 tag_type_ref,
38409 any_values,
38410 fields_len,
38411 zir,
38412 body_end,
38413 ) catch |err| switch (err) {
38414 error.GenericPoison => unreachable,
38415 error.ComptimeBreak => unreachable,
38416 error.ComptimeReturn => unreachable,
38417 error.OutOfMemory => |e| return e,
38418 error.AnalysisFail => {
38419 if (!zcu.failed_analysis.contains(sema.owner)) {
38420 try zcu.transitive_failed_analysis.put(gpa, sema.owner, {});
38421 }
38422 return error.AnalysisFail;
38423 },
38424 };
38425}
38426
38427fn resolveDeclaredEnumInner(
38428 sema: *Sema,
38429 block: *Block,
38430 wip_ty: InternPool.WipEnumType,
38431 inst: Zir.Inst.Index,
38432 tracked_inst: InternPool.TrackedInst.Index,
38433 src: LazySrcLoc,
38434 small: Zir.Inst.EnumDecl.Small,
38435 body: []const Zir.Inst.Index,
38436 tag_type_ref: Zir.Inst.Ref,
38437 any_values: bool,
38438 fields_len: u32,
38439 zir: Zir,
38440 body_end: usize,
38441) Zcu.CompileError!void {
38442 const pt = sema.pt;
38443 const zcu = pt.zcu;
38444 const gpa = zcu.gpa;
38445 const ip = &zcu.intern_pool;
38446
38447 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
38448
38449 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
38450
3838238451 const int_tag_ty = ty: {
3838338452 if (body.len != 0) {
38384 _ = try sema.analyzeInlineBody(&block, body, inst);
38453 _ = try sema.analyzeInlineBody(block, body, inst);
3838538454 }
3838638455
3838738456 if (tag_type_ref != .none) {
38388 const ty = try sema.resolveType(&block, tag_ty_src, tag_type_ref);
38457 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
3838938458 if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) {
38390 return sema.fail(&block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)});
38459 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)});
3839138460 }
3839238461 break :ty ty;
3839338462 } else if (fields_len == 0) {
......@@ -38402,7 +38471,7 @@ pub fn resolveDeclaredEnum(
3840238471
3840338472 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
3840438473 if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
38405 return sema.fail(&block, src, "non-exhaustive enum specifies every value", .{});
38474 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
3840638475 }
3840738476 }
3840838477
......@@ -38434,7 +38503,7 @@ pub fn resolveDeclaredEnum(
3843438503 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
3843538504 extra_index += 1;
3843638505 const tag_inst = try sema.resolveInst(tag_val_ref);
38437 last_tag_val = try sema.resolveConstDefinedValue(&block, .{
38506 last_tag_val = try sema.resolveConstDefinedValue(block, .{
3843838507 .base_node_inst = tracked_inst,
3843938508 .offset = .{ .container_field_name = field_i },
3844038509 }, tag_inst, .{ .simple = .enum_field_tag_value });
......@@ -38447,12 +38516,12 @@ pub fn resolveDeclaredEnum(
3844738516 .offset = .{ .container_field_value = conflict.prev_field_idx },
3844838517 };
3844938518 const msg = msg: {
38450 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)});
38519 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3845138520 errdefer msg.destroy(gpa);
3845238521 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3845338522 break :msg msg;
3845438523 };
38455 return sema.failWithOwnedErrorMsg(&block, msg);
38524 return sema.failWithOwnedErrorMsg(block, msg);
3845638525 }
3845738526 break :overflow false;
3845838527 } else if (any_values) overflow: {
......@@ -38469,12 +38538,12 @@ pub fn resolveDeclaredEnum(
3846938538 .offset = .{ .container_field_value = conflict.prev_field_idx },
3847038539 };
3847138540 const msg = msg: {
38472 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, &sema)});
38541 const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
3847338542 errdefer msg.destroy(gpa);
3847438543 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
3847538544 break :msg msg;
3847638545 };
38477 return sema.failWithOwnedErrorMsg(&block, msg);
38546 return sema.failWithOwnedErrorMsg(block, msg);
3847838547 }
3847938548 break :overflow false;
3848038549 } else overflow: {
......@@ -38487,9 +38556,9 @@ pub fn resolveDeclaredEnum(
3848738556
3848838557 if (tag_overflow) {
3848938558 const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{
38490 last_tag_val.?.fmtValueSema(pt, &sema), int_tag_ty.fmt(pt),
38559 last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt),
3849138560 });
38492 return sema.failWithOwnedErrorMsg(&block, msg);
38561 return sema.failWithOwnedErrorMsg(block, msg);
3849338562 }
3849438563 }
3849538564}
src/Zcu/PerThread.zig+8-6
......@@ -3669,6 +3669,8 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo
36693669/// If the type cannot be recreated because it has been lost, `error.AnalysisFail` is returned.
36703670/// If `ty` is not outdated, that same `InternPool.Index` is returned.
36713671/// If `ty` has already been replaced by this function, the new index will not be returned again.
3672/// Also, if `ty` is an enum, this function will resolve the new type if needed, and the call site
3673/// is responsible for checking `[transitive_]failed_analysis` to detect resolution failures.
36723674pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index {
36733675 const zcu = pt.zcu;
36743676 const gpa = zcu.gpa;
......@@ -3878,12 +3880,14 @@ fn recreateUnionType(
38783880 return wip_ty.finish(ip, namespace_index);
38793881}
38803882
3881// TODO: is it safe for this to return `SemaError`? enum type resolution is a bit weird...
3883/// This *does* call `Sema.resolveDeclaredEnum`, but errors from it are not propagated.
3884/// Call sites are resposible for checking `[transitive_]failed_analysis` after `ensureTypeUpToDate`
3885/// returns in order to detect resolution failures.
38823886fn recreateEnumType(
38833887 pt: Zcu.PerThread,
38843888 old_ty: InternPool.Index,
38853889 key: InternPool.Key.NamespaceType.Declared,
3886) Zcu.SemaError!InternPool.Index {
3890) Allocator.Error!InternPool.Index {
38873891 const zcu = pt.zcu;
38883892 const gpa = zcu.gpa;
38893893 const ip = &zcu.intern_pool;
......@@ -3993,10 +3997,8 @@ fn recreateEnumType(
39933997 zir,
39943998 body_end,
39953999 ) catch |err| switch (err) {
3996 error.GenericPoison => unreachable,
3997 error.ComptimeBreak => unreachable,
3998 error.ComptimeReturn => unreachable,
3999 error.AnalysisFail, error.OutOfMemory => |e| return e,
4000 error.OutOfMemory => |e| return e,
4001 error.AnalysisFail => {}, // call sites are responsible for checking `[transitive_]failed_analysis` to detect this
40004002 };
40014003
40024004 return wip_ty.index;
test/behavior/union.zig+19
......@@ -2303,3 +2303,22 @@ test "extern union @FieldType" {
23032303 comptime assert(@FieldType(U, "b") == f64);
23042304 comptime assert(@FieldType(U, "c") == *U);
23052305}
2306
2307test "assign global tagged union" {
2308 const U = union(enum) {
2309 a: u16,
2310 b: u32,
2311
2312 var global: @This() = undefined;
2313 };
2314
2315 U.global = .{ .a = 123 };
2316 try expect(U.global == .a);
2317 try expect(U.global != .b);
2318 try expect(U.global.a == 123);
2319
2320 U.global = .{ .b = 123456 };
2321 try expect(U.global != .a);
2322 try expect(U.global == .b);
2323 try expect(U.global.b == 123456);
2324}
test/incremental/change_enum_tag_type created+59
......@@ -0,0 +1,59 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted
5#update=initial version
6#file=main.zig
7const Tag = u2;
8const Foo = enum(Tag) {
9 a,
10 b,
11 c,
12 d,
13};
14pub fn main() !void {
15 var val: Foo = undefined;
16 val = .a;
17 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
18}
19const std = @import("std");
20#expect_stdout="a\n"
21#update=too many enum fields
22#file=main.zig
23const Tag = u2;
24const Foo = enum(Tag) {
25 a,
26 b,
27 c,
28 d,
29 e,
30};
31pub fn main() !void {
32 var val: Foo = undefined;
33 val = .a;
34 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
35}
36comptime {
37 // These can't be true at the same time; analysis should stop as soon as it sees `Foo`
38 std.debug.assert(@intFromEnum(Foo.e) == 4);
39 std.debug.assert(@TypeOf(@intFromEnum(Foo.e)) == Tag);
40}
41const std = @import("std");
42#expect_error=ignored
43#update=increase tag size
44#file=main.zig
45const Tag = u3;
46const Foo = enum(Tag) {
47 a,
48 b,
49 c,
50 d,
51 e,
52};
53pub fn main() !void {
54 var val: Foo = undefined;
55 val = .a;
56 try std.io.getStdOut().writer().print("{s}\n", .{@tagName(val)});
57}
58const std = @import("std");
59#expect_stdout="a\n"