authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-03-03 22:18:28+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-03-03 22:18:28+00:00
logc76f451abc0e642972e85d426112f494d30d40c7
treee95dd64cf42a2525d0b2b6474dd4b74ab841eb44
parent501e84a96aa18fae7c345b0b54efa652cea85b38
parent3aaf39424905801a4717df3e184c693f5373e09c
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22979 from mlugg/remove-legacy-coercions

Sema: remove legacy coercion

6 files changed, 45 insertions(+), 133 deletions(-)

lib/std/compress/lzma/decode.zig+17-17
...@@ -112,17 +112,17 @@ pub const DecoderState = struct {...@@ -112,17 +112,17 @@ pub const DecoderState = struct {
112 .lzma_props = lzma_props,112 .lzma_props = lzma_props,
113 .unpacked_size = unpacked_size,113 .unpacked_size = unpacked_size,
114 .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }),114 .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }),
115 .pos_slot_decoder = .{.{}} ** 4,115 .pos_slot_decoder = @splat(.{}),
116 .align_decoder = .{},116 .align_decoder = .{},
117 .pos_decoders = .{0x400} ** 115,117 .pos_decoders = @splat(0x400),
118 .is_match = .{0x400} ** 192,118 .is_match = @splat(0x400),
119 .is_rep = .{0x400} ** 12,119 .is_rep = @splat(0x400),
120 .is_rep_g0 = .{0x400} ** 12,120 .is_rep_g0 = @splat(0x400),
121 .is_rep_g1 = .{0x400} ** 12,121 .is_rep_g1 = @splat(0x400),
122 .is_rep_g2 = .{0x400} ** 12,122 .is_rep_g2 = @splat(0x400),
123 .is_rep_0long = .{0x400} ** 192,123 .is_rep_0long = @splat(0x400),
124 .state = 0,124 .state = 0,
125 .rep = .{0} ** 4,125 .rep = @splat(0),
126 .len_decoder = .{},126 .len_decoder = .{},
127 .rep_len_decoder = .{},127 .rep_len_decoder = .{},
128 };128 };
...@@ -145,15 +145,15 @@ pub const DecoderState = struct {...@@ -145,15 +145,15 @@ pub const DecoderState = struct {
145 self.lzma_props = new_props;145 self.lzma_props = new_props;
146 for (&self.pos_slot_decoder) |*t| t.reset();146 for (&self.pos_slot_decoder) |*t| t.reset();
147 self.align_decoder.reset();147 self.align_decoder.reset();
148 self.pos_decoders = .{0x400} ** 115;148 self.pos_decoders = @splat(0x400);
149 self.is_match = .{0x400} ** 192;149 self.is_match = @splat(0x400);
150 self.is_rep = .{0x400} ** 12;150 self.is_rep = @splat(0x400);
151 self.is_rep_g0 = .{0x400} ** 12;151 self.is_rep_g0 = @splat(0x400);
152 self.is_rep_g1 = .{0x400} ** 12;152 self.is_rep_g1 = @splat(0x400);
153 self.is_rep_g2 = .{0x400} ** 12;153 self.is_rep_g2 = @splat(0x400);
154 self.is_rep_0long = .{0x400} ** 192;154 self.is_rep_0long = @splat(0x400);
155 self.state = 0;155 self.state = 0;
156 self.rep = .{0} ** 4;156 self.rep = @splat(0);
157 self.len_decoder.reset();157 self.len_decoder.reset();
158 self.rep_len_decoder.reset();158 self.rep_len_decoder.reset();
159 }159 }
lib/std/compress/lzma/decode/rangecoder.zig+3-3
...@@ -120,7 +120,7 @@ pub const RangeDecoder = struct {...@@ -120,7 +120,7 @@ pub const RangeDecoder = struct {
120120
121pub fn BitTree(comptime num_bits: usize) type {121pub fn BitTree(comptime num_bits: usize) type {
122 return struct {122 return struct {
123 probs: [1 << num_bits]u16 = .{0x400} ** (1 << num_bits),123 probs: [1 << num_bits]u16 = @splat(0x400),
124124
125 const Self = @This();125 const Self = @This();
126126
...@@ -151,8 +151,8 @@ pub fn BitTree(comptime num_bits: usize) type {...@@ -151,8 +151,8 @@ pub fn BitTree(comptime num_bits: usize) type {
151pub const LenDecoder = struct {151pub const LenDecoder = struct {
152 choice: u16 = 0x400,152 choice: u16 = 0x400,
153 choice2: u16 = 0x400,153 choice2: u16 = 0x400,
154 low_coder: [16]BitTree(3) = .{.{}} ** 16,154 low_coder: [16]BitTree(3) = @splat(.{}),
155 mid_coder: [16]BitTree(3) = .{.{}} ** 16,155 mid_coder: [16]BitTree(3) = @splat(.{}),
156 high_coder: BitTree(8) = .{},156 high_coder: BitTree(8) = .{},
157157
158 pub fn decode(158 pub fn decode(
src/Sema.zig+2-110
...@@ -30053,8 +30053,8 @@ fn coerceExtra(...@@ -30053,8 +30053,8 @@ fn coerceExtra(
30053 else => {},30053 else => {},
30054 },30054 },
30055 .@"struct" => blk: {30055 .@"struct" => blk: {
30056 if (inst_ty.isTuple(zcu)) {30056 if (dest_ty.isTuple(zcu) and inst_ty.isTuple(zcu)) {
30057 return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {30057 return sema.coerceTupleToTuple(block, dest_ty, inst, inst_src) catch |err| switch (err) {
30058 error.NotCoercible => break :blk,30058 error.NotCoercible => break :blk,
30059 else => |e| return e,30059 else => |e| return e,
30060 };30060 };
...@@ -32135,114 +32135,6 @@ fn coerceTupleToArrayPtrs(...@@ -32135,114 +32135,6 @@ fn coerceTupleToArrayPtrs(
32135 return ptr_array;32135 return ptr_array;
32136}32136}
3213732137
32138/// Handles both tuples and anon struct literals. Coerces field-wise. Reports
32139/// errors for both extra fields and missing fields.
32140fn coerceTupleToStruct(
32141 sema: *Sema,
32142 block: *Block,
32143 struct_ty: Type,
32144 inst: Air.Inst.Ref,
32145 inst_src: LazySrcLoc,
32146) !Air.Inst.Ref {
32147 const pt = sema.pt;
32148 const zcu = pt.zcu;
32149 const ip = &zcu.intern_pool;
32150 try struct_ty.resolveFields(pt);
32151 try struct_ty.resolveStructFieldInits(pt);
32152
32153 if (struct_ty.isTuple(zcu)) {
32154 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
32155 }
32156
32157 const struct_type = zcu.typeToStruct(struct_ty).?;
32158 const field_vals = try sema.arena.alloc(InternPool.Index, struct_type.field_types.len);
32159 const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
32160 @memset(field_refs, .none);
32161
32162 const inst_ty = sema.typeOf(inst);
32163 var runtime_src: ?LazySrcLoc = null;
32164 const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
32165 .tuple_type => |tuple| tuple.types.len,
32166 .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
32167 else => unreachable,
32168 };
32169 for (0..field_count) |tuple_field_index| {
32170 const field_src = inst_src; // TODO better source location
32171 const field_name = inst_ty.structFieldName(tuple_field_index, zcu).unwrap() orelse
32172 try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{d}", .{tuple_field_index}, .no_embedded_nulls);
32173
32174 const struct_field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
32175 const struct_field_ty = Type.fromInterned(struct_type.field_types.get(ip)[struct_field_index]);
32176 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, @intCast(tuple_field_index));
32177 const coerced = try sema.coerce(block, struct_field_ty, elem_ref, field_src);
32178 field_refs[struct_field_index] = coerced;
32179 if (struct_type.fieldIsComptime(ip, struct_field_index)) {
32180 const init_val = try sema.resolveValue(coerced) orelse {
32181 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
32182 };
32183
32184 const field_init = Value.fromInterned(struct_type.field_inits.get(ip)[struct_field_index]);
32185 if (!init_val.eql(field_init, struct_field_ty, pt.zcu)) {
32186 return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, tuple_field_index);
32187 }
32188 }
32189 if (runtime_src == null) {
32190 if (try sema.resolveValue(coerced)) |field_val| {
32191 field_vals[struct_field_index] = field_val.toIntern();
32192 } else {
32193 runtime_src = field_src;
32194 }
32195 }
32196 }
32197
32198 // Populate default field values and report errors for missing fields.
32199 var root_msg: ?*Zcu.ErrorMsg = null;
32200 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
32201
32202 for (field_refs, 0..) |*field_ref, i| {
32203 if (field_ref.* != .none) continue;
32204
32205 const field_name = struct_type.field_names.get(ip)[i];
32206 const field_default_val = struct_type.fieldInit(ip, i);
32207 const field_src = inst_src; // TODO better source location
32208 if (field_default_val == .none) {
32209 const template = "missing struct field: {}";
32210 const args = .{field_name.fmt(ip)};
32211 if (root_msg) |msg| {
32212 try sema.errNote(field_src, msg, template, args);
32213 } else {
32214 root_msg = try sema.errMsg(field_src, template, args);
32215 }
32216 continue;
32217 }
32218 if (runtime_src == null) {
32219 field_vals[i] = field_default_val;
32220 } else {
32221 field_ref.* = Air.internedToRef(field_default_val);
32222 }
32223 }
32224
32225 if (root_msg) |msg| {
32226 try sema.addDeclaredHereNote(msg, struct_ty);
32227 root_msg = null;
32228 return sema.failWithOwnedErrorMsg(block, msg);
32229 }
32230
32231 if (runtime_src) |rs| {
32232 try sema.requireRuntimeBlock(block, inst_src, rs);
32233 return block.addAggregateInit(struct_ty, field_refs);
32234 }
32235
32236 const struct_val = try pt.intern(.{ .aggregate = .{
32237 .ty = struct_ty.toIntern(),
32238 .storage = .{ .elems = field_vals },
32239 } });
32240 // TODO: figure out InternPool removals for incremental compilation
32241 //errdefer ip.remove(struct_val);
32242
32243 return Air.internedToRef(struct_val);
32244}
32245
32246fn coerceTupleToTuple(32138fn coerceTupleToTuple(
32247 sema: *Sema,32139 sema: *Sema,
32248 block: *Block,32140 block: *Block,
test/behavior/tuple.zig+1-1
...@@ -405,7 +405,7 @@ test "tuple of struct concatenation and coercion to array" {...@@ -405,7 +405,7 @@ test "tuple of struct concatenation and coercion to array" {
405 const SomeStruct = struct { array: [4]StructWithDefault };405 const SomeStruct = struct { array: [4]StructWithDefault };
406406
407 const value1 = SomeStruct{ .array = .{StructWithDefault{}} ++ [_]StructWithDefault{.{}} ** 3 };407 const value1 = SomeStruct{ .array = .{StructWithDefault{}} ++ [_]StructWithDefault{.{}} ** 3 };
408 const value2 = SomeStruct{ .array = .{.{}} ++ [_]StructWithDefault{.{}} ** 3 };408 const value2 = SomeStruct{ .array = .{ .{}, .{}, .{}, .{} } };
409409
410 try expectEqual(value1, value2);410 try expectEqual(value1, value2);
411}411}
test/cases/compile_errors/coerce_empty_tuple_to_struct.zig created+21
...@@ -0,0 +1,21 @@
1const empty = .{};
2
3const Foo = struct {};
4const foo: Foo = empty;
5
6const Bar = struct { a: u32 };
7const bar: Bar = empty;
8
9comptime {
10 _ = foo;
11}
12comptime {
13 _ = bar;
14}
15
16// error
17//
18// :4:18: error: expected type 'tmp.Foo', found '@TypeOf(.{})'
19// :3:13: note: struct declared here
20// :7:18: error: expected type 'tmp.Bar', found '@TypeOf(.{})'
21// :6:13: note: struct declared here
test/cases/compile_errors/invalid_tuple_to_struct_coercion.zig+1-2
...@@ -7,7 +7,6 @@ export fn entry() void {...@@ -7,7 +7,6 @@ export fn entry() void {
7}7}
88
9// error9// error
10// target=native
11//10//
12// :6:31: error: no field named '0' in struct 'tmp.S'11// :6:31: error: expected type 'tmp.S', found 'struct { comptime void = {} }'
13// :1:11: note: struct declared here12// :1:11: note: struct declared here