From 84da520c44e9d944fec4f8f54655b1942acb36c7 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sat, 22 Feb 2025 22:06:08 +0000 Subject: [PATCH 1/3] Sema: remove legacy coercion This was meant to be removed in #21817, but was somehow missed. --- src/Sema.zig | 112 +----------------- .../coerce_empty_tuple_to_struct.zig | 21 ++++ 2 files changed, 23 insertions(+), 110 deletions(-) create mode 100644 test/cases/compile_errors/coerce_empty_tuple_to_struct.zig diff --git a/src/Sema.zig b/src/Sema.zig index 9e729a17eabe..b30f42c2d7b5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -30053,8 +30053,8 @@ fn coerceExtra( else => {}, }, .@"struct" => blk: { - if (inst_ty.isTuple(zcu)) { - return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) { + if (dest_ty.isTuple(zcu) and inst_ty.isTuple(zcu)) { + return sema.coerceTupleToTuple(block, dest_ty, inst, inst_src) catch |err| switch (err) { error.NotCoercible => break :blk, else => |e| return e, }; @@ -32135,114 +32135,6 @@ fn coerceTupleToArrayPtrs( return ptr_array; } -/// Handles both tuples and anon struct literals. Coerces field-wise. Reports -/// errors for both extra fields and missing fields. -fn coerceTupleToStruct( - sema: *Sema, - block: *Block, - struct_ty: Type, - inst: Air.Inst.Ref, - inst_src: LazySrcLoc, -) !Air.Inst.Ref { - const pt = sema.pt; - const zcu = pt.zcu; - const ip = &zcu.intern_pool; - try struct_ty.resolveFields(pt); - try struct_ty.resolveStructFieldInits(pt); - - if (struct_ty.isTuple(zcu)) { - return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); - } - - const struct_type = zcu.typeToStruct(struct_ty).?; - const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len); - const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); - @memset(field_refs, .none); - - const inst_ty = sema.typeOf(inst); - var runtime_src: ?LazySrcLoc = null; - const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { - .tuple_type => |tuple| tuple.types.len, - .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len, - else => unreachable, - }; - for (0..field_count) |tuple_field_index| { - const field_src = inst_src; // TODO better source location - const field_name = inst_ty.structFieldName(tuple_field_index, zcu).unwrap() orelse - try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{d}", .{tuple_field_index}, .no_embedded_nulls); - - const struct_field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); - const struct_field_ty = Type.fromInterned(struct_type.field_types.get(ip)[struct_field_index]); - const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, @intCast(tuple_field_index)); - const coerced = try sema.coerce(block, struct_field_ty, elem_ref, field_src); - field_refs[struct_field_index] = coerced; - if (struct_type.fieldIsComptime(ip, struct_field_index)) { - const init_val = try sema.resolveValue(coerced) orelse { - return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); - }; - - const field_init = Value.fromInterned(struct_type.field_inits.get(ip)[struct_field_index]); - if (!init_val.eql(field_init, struct_field_ty, pt.zcu)) { - return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, tuple_field_index); - } - } - if (runtime_src == null) { - if (try sema.resolveValue(coerced)) |field_val| { - field_vals[struct_field_index] = field_val.toIntern(); - } else { - runtime_src = field_src; - } - } - } - - // Populate default field values and report errors for missing fields. - var root_msg: ?*Zcu.ErrorMsg = null; - errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - - for (field_refs, 0..) |*field_ref, i| { - if (field_ref.* != .none) continue; - - const field_name = struct_type.field_names.get(ip)[i]; - const field_default_val = struct_type.fieldInit(ip, i); - const field_src = inst_src; // TODO better source location - if (field_default_val == .none) { - const template = "missing struct field: {}"; - const args = .{field_name.fmt(ip)}; - if (root_msg) |msg| { - try sema.errNote(field_src, msg, template, args); - } else { - root_msg = try sema.errMsg(field_src, template, args); - } - continue; - } - if (runtime_src == null) { - field_vals[i] = field_default_val; - } else { - field_ref.* = Air.internedToRef(field_default_val); - } - } - - if (root_msg) |msg| { - try sema.addDeclaredHereNote(msg, struct_ty); - root_msg = null; - return sema.failWithOwnedErrorMsg(block, msg); - } - - if (runtime_src) |rs| { - try sema.requireRuntimeBlock(block, inst_src, rs); - return block.addAggregateInit(struct_ty, field_refs); - } - - const struct_val = try pt.intern(.{ .aggregate = .{ - .ty = struct_ty.toIntern(), - .storage = .{ .elems = field_vals }, - } }); - // TODO: figure out InternPool removals for incremental compilation - //errdefer ip.remove(struct_val); - - return Air.internedToRef(struct_val); -} - fn coerceTupleToTuple( sema: *Sema, block: *Block, diff --git a/test/cases/compile_errors/coerce_empty_tuple_to_struct.zig b/test/cases/compile_errors/coerce_empty_tuple_to_struct.zig new file mode 100644 index 000000000000..9ed4ece3daad --- /dev/null +++ b/test/cases/compile_errors/coerce_empty_tuple_to_struct.zig @@ -0,0 +1,21 @@ +const empty = .{}; + +const Foo = struct {}; +const foo: Foo = empty; + +const Bar = struct { a: u32 }; +const bar: Bar = empty; + +comptime { + _ = foo; +} +comptime { + _ = bar; +} + +// error +// +// :4:18: error: expected type 'tmp.Foo', found '@TypeOf(.{})' +// :3:13: note: struct declared here +// :7:18: error: expected type 'tmp.Bar', found '@TypeOf(.{})' +// :6:13: note: struct declared here From 8e074f1549779a5c19dccedfb379c53cd01914d3 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sun, 23 Feb 2025 13:00:14 +0000 Subject: [PATCH 2/3] std: remove dependencies on legacy coercion --- lib/std/compress/lzma/decode.zig | 34 ++++++++++----------- lib/std/compress/lzma/decode/rangecoder.zig | 6 ++-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/std/compress/lzma/decode.zig b/lib/std/compress/lzma/decode.zig index ec0619ba57e2..ac45eb52b39f 100644 --- a/lib/std/compress/lzma/decode.zig +++ b/lib/std/compress/lzma/decode.zig @@ -112,17 +112,17 @@ pub const DecoderState = struct { .lzma_props = lzma_props, .unpacked_size = unpacked_size, .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }), - .pos_slot_decoder = .{.{}} ** 4, + .pos_slot_decoder = @splat(.{}), .align_decoder = .{}, - .pos_decoders = .{0x400} ** 115, - .is_match = .{0x400} ** 192, - .is_rep = .{0x400} ** 12, - .is_rep_g0 = .{0x400} ** 12, - .is_rep_g1 = .{0x400} ** 12, - .is_rep_g2 = .{0x400} ** 12, - .is_rep_0long = .{0x400} ** 192, + .pos_decoders = @splat(0x400), + .is_match = @splat(0x400), + .is_rep = @splat(0x400), + .is_rep_g0 = @splat(0x400), + .is_rep_g1 = @splat(0x400), + .is_rep_g2 = @splat(0x400), + .is_rep_0long = @splat(0x400), .state = 0, - .rep = .{0} ** 4, + .rep = @splat(0), .len_decoder = .{}, .rep_len_decoder = .{}, }; @@ -145,15 +145,15 @@ pub const DecoderState = struct { self.lzma_props = new_props; for (&self.pos_slot_decoder) |*t| t.reset(); self.align_decoder.reset(); - self.pos_decoders = .{0x400} ** 115; - self.is_match = .{0x400} ** 192; - self.is_rep = .{0x400} ** 12; - self.is_rep_g0 = .{0x400} ** 12; - self.is_rep_g1 = .{0x400} ** 12; - self.is_rep_g2 = .{0x400} ** 12; - self.is_rep_0long = .{0x400} ** 192; + self.pos_decoders = @splat(0x400); + self.is_match = @splat(0x400); + self.is_rep = @splat(0x400); + self.is_rep_g0 = @splat(0x400); + self.is_rep_g1 = @splat(0x400); + self.is_rep_g2 = @splat(0x400); + self.is_rep_0long = @splat(0x400); self.state = 0; - self.rep = .{0} ** 4; + self.rep = @splat(0); self.len_decoder.reset(); self.rep_len_decoder.reset(); } diff --git a/lib/std/compress/lzma/decode/rangecoder.zig b/lib/std/compress/lzma/decode/rangecoder.zig index 515420a7d425..01930884d709 100644 --- a/lib/std/compress/lzma/decode/rangecoder.zig +++ b/lib/std/compress/lzma/decode/rangecoder.zig @@ -120,7 +120,7 @@ pub const RangeDecoder = struct { pub fn BitTree(comptime num_bits: usize) type { return struct { - probs: [1 << num_bits]u16 = .{0x400} ** (1 << num_bits), + probs: [1 << num_bits]u16 = @splat(0x400), const Self = @This(); @@ -151,8 +151,8 @@ pub fn BitTree(comptime num_bits: usize) type { pub const LenDecoder = struct { choice: u16 = 0x400, choice2: u16 = 0x400, - low_coder: [16]BitTree(3) = .{.{}} ** 16, - mid_coder: [16]BitTree(3) = .{.{}} ** 16, + low_coder: [16]BitTree(3) = @splat(.{}), + mid_coder: [16]BitTree(3) = @splat(.{}), high_coder: BitTree(8) = .{}, pub fn decode( From 3aaf39424905801a4717df3e184c693f5373e09c Mon Sep 17 00:00:00 2001 From: mlugg Date: Tue, 25 Feb 2025 16:27:43 +0000 Subject: [PATCH 3/3] test: remove dependencies on legacy coercion --- test/behavior/tuple.zig | 2 +- test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 80bf5ccd1eca..0a0ed1d62046 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -405,7 +405,7 @@ test "tuple of struct concatenation and coercion to array" { const SomeStruct = struct { array: [4]StructWithDefault }; const value1 = SomeStruct{ .array = .{StructWithDefault{}} ++ [_]StructWithDefault{.{}} ** 3 }; - const value2 = SomeStruct{ .array = .{.{}} ++ [_]StructWithDefault{.{}} ** 3 }; + const value2 = SomeStruct{ .array = .{ .{}, .{}, .{}, .{} } }; try expectEqual(value1, value2); } diff --git a/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig b/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig index 4f25a26ef108..1c691f76ea5a 100644 --- a/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig +++ b/test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig @@ -7,7 +7,6 @@ export fn entry() void { } // error -// target=native // -// :6:31: error: no field named '0' in struct 'tmp.S' +// :6:31: error: expected type 'tmp.S', found 'struct { comptime void = {} }' // :1:11: note: struct declared here