authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-02-06 22:19:25+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-02-06 22:19:25+00:00
log43e52ec5c5a2267791cb2aaaf37f3f84dbe29d25
treef161e86b9ae7f9c2b764345782db302373eee908
parentb0ed602d5d9358128471588f00a073f2545809fa
parent5d935e1137ade5450e504ce9bc6bbf32301b0dfd
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22777 from mlugg/some-bugs

Fix a bunch of frontend bugs

19 files changed, 395 insertions(+), 74 deletions(-)

lib/std/zig/AstGen.zig+5-1
......@@ -920,7 +920,10 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
920920 const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
921921 const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.start);
922922 const end = if (full.ast.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, full.ast.end) else .none;
923 const sentinel = if (full.ast.sentinel != 0) try expr(gz, scope, .{ .rl = .none }, full.ast.sentinel) else .none;
923 const sentinel = if (full.ast.sentinel != 0) s: {
924 const sentinel_ty = try gz.addUnNode(.slice_sentinel_ty, lhs, node);
925 break :s try expr(gz, scope, .{ .rl = .{ .coerced_ty = sentinel_ty } }, full.ast.sentinel);
926 } else .none;
924927 try emitDbgStmt(gz, cursor);
925928 if (sentinel != .none) {
926929 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
......@@ -2855,6 +2858,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
28552858 .slice_end,
28562859 .slice_sentinel,
28572860 .slice_length,
2861 .slice_sentinel_ty,
28582862 .import,
28592863 .switch_block,
28602864 .switch_block_ref,
lib/std/zig/Zir.zig+8
......@@ -599,6 +599,10 @@ pub const Inst = struct {
599599 /// Returns a pointer to the subslice.
600600 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceLength`.
601601 slice_length,
602 /// Given a value which is a pointer to the LHS of a slice operation, return the sentinel
603 /// type, used as the result type of the slice sentinel (i.e. `s` in `lhs[a..b :s]`).
604 /// Uses the `un_node` field. AST node is the slice syntax. Operand is `lhs`.
605 slice_sentinel_ty,
602606 /// Same as `store` except provides a source location.
603607 /// Uses the `pl_node` union field. Payload is `Bin`.
604608 store_node,
......@@ -1185,6 +1189,7 @@ pub const Inst = struct {
11851189 .slice_end,
11861190 .slice_sentinel,
11871191 .slice_length,
1192 .slice_sentinel_ty,
11881193 .import,
11891194 .typeof_log2_int_type,
11901195 .resolve_inferred_alloc,
......@@ -1472,6 +1477,7 @@ pub const Inst = struct {
14721477 .slice_end,
14731478 .slice_sentinel,
14741479 .slice_length,
1480 .slice_sentinel_ty,
14751481 .import,
14761482 .typeof_log2_int_type,
14771483 .switch_block,
......@@ -1702,6 +1708,7 @@ pub const Inst = struct {
17021708 .slice_end = .pl_node,
17031709 .slice_sentinel = .pl_node,
17041710 .slice_length = .pl_node,
1711 .slice_sentinel_ty = .un_node,
17051712 .store_node = .pl_node,
17061713 .store_to_inferred_ptr = .pl_node,
17071714 .str = .str,
......@@ -4162,6 +4169,7 @@ fn findTrackableInner(
41624169 .slice_end,
41634170 .slice_sentinel,
41644171 .slice_length,
4172 .slice_sentinel_ty,
41654173 .store_node,
41664174 .store_to_inferred_ptr,
41674175 .str,
src/Compilation.zig+6-4
......@@ -2196,6 +2196,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
21962196
21972197 zcu.compile_log_text.shrinkAndFree(gpa, 0);
21982198
2199 zcu.skip_analysis_errors = false;
2200
21992201 // Make sure std.zig is inside the import_table. We unconditionally need
22002202 // it for start.zig.
22012203 const std_mod = zcu.std_mod;
......@@ -3208,7 +3210,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
32083210 });
32093211 }
32103212
3211 if (comp.zcu) |zcu| {
3213 if (comp.zcu) |zcu| zcu_errors: {
32123214 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
32133215 if (error_msg) |msg| {
32143216 try addModuleErrorMsg(zcu, &bundle, msg.*);
......@@ -3225,6 +3227,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
32253227 }
32263228 }
32273229 }
3230 if (zcu.skip_analysis_errors) break :zcu_errors;
32283231 var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: {
32293232 const SortOrder = struct {
32303233 zcu: *Zcu,
......@@ -3360,7 +3363,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
33603363 try comp.link_diags.addMessagesToBundle(&bundle, comp.bin_file);
33613364
33623365 if (comp.zcu) |zcu| {
3363 if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) {
3366 if (!zcu.skip_analysis_errors and bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) {
33643367 const values = zcu.compile_log_sources.values();
33653368 // First one will be the error; subsequent ones will be notes.
33663369 const src_loc = values[0].src();
......@@ -3861,10 +3864,9 @@ fn performAllTheWorkInner(
38613864 // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
38623865 // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
38633866 // However, this means our analysis data is invalid, so we want to omit all analysis errors.
3864 // To do that, let's just clear the analysis roots!
38653867
38663868 assert(zcu.failed_files.count() > 0); // we will get an error
3867 zcu.analysis_roots.clear(); // no analysis happened
3869 zcu.skip_analysis_errors = true;
38683870 return;
38693871 }
38703872
src/InternPool.zig+1-1
......@@ -4011,7 +4011,7 @@ pub const LoadedStructType = struct {
40114011
40124012 pub fn haveFieldTypes(s: LoadedStructType, ip: *const InternPool) bool {
40134013 const types = s.field_types.get(ip);
4014 return types.len == 0 or types[0] != .none;
4014 return types.len == 0 or types[types.len - 1] != .none;
40154015 }
40164016
40174017 pub fn haveFieldInits(s: LoadedStructType, ip: *const InternPool) bool {
src/Sema.zig+171-65
......@@ -504,7 +504,17 @@ pub const Block = struct {
504504 };
505505 }
506506
507 pub fn wantSafety(block: *const Block) bool {
507 fn wantSafeTypes(block: *const Block) bool {
508 return block.want_safety orelse switch (block.sema.pt.zcu.optimizeMode()) {
509 .Debug => true,
510 .ReleaseSafe => true,
511 .ReleaseFast => false,
512 .ReleaseSmall => false,
513 };
514 }
515
516 fn wantSafety(block: *const Block) bool {
517 if (block.isComptime()) return false; // runtime safety checks are pointless in comptime blocks
508518 return block.want_safety orelse switch (block.sema.pt.zcu.optimizeMode()) {
509519 .Debug => true,
510520 .ReleaseSafe => true,
......@@ -1197,6 +1207,7 @@ fn analyzeBodyInner(
11971207 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
11981208 .slice_start => try sema.zirSliceStart(block, inst),
11991209 .slice_length => try sema.zirSliceLength(block, inst),
1210 .slice_sentinel_ty => try sema.zirSliceSentinelTy(block, inst),
12001211 .str => try sema.zirStr(inst),
12011212 .switch_block => try sema.zirSwitchBlock(block, inst, false),
12021213 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
......@@ -3293,7 +3304,7 @@ fn zirUnionDecl(
32933304 .tagged
32943305 else if (small.layout != .auto)
32953306 .none
3296 else switch (block.wantSafety()) {
3307 else switch (block.wantSafeTypes()) {
32973308 true => .safety,
32983309 false => .none,
32993310 },
......@@ -9144,6 +9155,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
91449155 return sema.analyzeErrUnionCode(block, src, operand);
91459156}
91469157
9158/// If `operand` is comptime-known, asserts that it is an error value rather than a payload value.
91479159fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref {
91489160 const pt = sema.pt;
91499161 const zcu = pt.zcu;
......@@ -10753,6 +10765,46 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1075310765 return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
1075410766}
1075510767
10768fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
10769 const tracy = trace(@src());
10770 defer tracy.end();
10771
10772 const pt = sema.pt;
10773 const zcu = pt.zcu;
10774
10775 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
10776
10777 const src = block.nodeOffset(inst_data.src_node);
10778 const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
10779 const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node });
10780
10781 // This is like the logic in `analyzeSlice`; since we've evaluated the LHS as an lvalue, we will
10782 // have a double pointer if it was already a pointer.
10783
10784 const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand));
10785 const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) {
10786 .pointer => lhs_ptr_ty.childType(zcu),
10787 else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}),
10788 };
10789
10790 const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) {
10791 .array => lhs_ty.childType(zcu),
10792 .pointer => switch (lhs_ty.ptrSize(zcu)) {
10793 .many, .c, .slice => lhs_ty.childType(zcu),
10794 .one => s: {
10795 const lhs_elem_ty = lhs_ty.childType(zcu);
10796 break :s switch (lhs_elem_ty.zigTypeTag(zcu)) {
10797 .array => lhs_elem_ty.childType(zcu), // array element type
10798 else => return sema.fail(block, sentinel_src, "slice of single-item pointer cannot have sentinel", .{}),
10799 };
10800 },
10801 },
10802 else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}),
10803 };
10804
10805 return Air.internedToRef(sentinel_ty.toIntern());
10806}
10807
1075610808/// Holds common data used when analyzing or resolving switch prong bodies,
1075710809/// including setting up captures.
1075810810const SwitchProngAnalysis = struct {
......@@ -17558,10 +17610,16 @@ fn analyzeCmp(
1755817610 return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
1755917611 }
1756017612 if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_union and rhs_ty.zigTypeTag(zcu) == .error_set) {
17613 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
17614 if (lhs_val.errorUnionIsPayload(zcu)) return .bool_false;
17615 }
1756117616 const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs);
1756217617 return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src);
1756317618 }
1756417619 if (is_equality_cmp and lhs_ty.zigTypeTag(zcu) == .error_set and rhs_ty.zigTypeTag(zcu) == .error_union) {
17620 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {
17621 if (rhs_val.errorUnionIsPayload(zcu)) return .bool_false;
17622 }
1756517623 const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs);
1756617624 return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src);
1756717625 }
......@@ -18087,10 +18145,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1808718145
1808818146 const ret_ty_opt = try pt.intern(.{ .opt = .{
1808918147 .ty = try pt.intern(.{ .opt_type = .type_type }),
18090 .val = if (func_ty_info.return_type == .generic_poison_type)
18091 .none
18092 else
18093 func_ty_info.return_type,
18148 .val = opt_val: {
18149 const ret_ty: Type = .fromInterned(func_ty_info.return_type);
18150 if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none;
18151 if (ret_ty.zigTypeTag(zcu) == .error_union) {
18152 if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) {
18153 break :opt_val .none;
18154 }
18155 }
18156 break :opt_val ret_ty.toIntern();
18157 },
1809418158 } });
1809518159
1809618160 const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
......@@ -21401,7 +21465,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2140121465 try operand_ty.resolveLayout(pt);
2140221466 const enum_ty = switch (operand_ty.zigTypeTag(zcu)) {
2140321467 .enum_literal => {
21404 const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, operand, undefined);
21468 const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?;
2140521469 const tag_name = ip.indexToKey(val.toIntern()).enum_literal;
2140621470 return sema.addNullTerminatedStrLit(tag_name);
2140721471 },
......@@ -22171,7 +22235,7 @@ fn reifyUnion(
2217122235 .tagged
2217222236 else if (layout != .auto)
2217322237 .none
22174 else switch (block.wantSafety()) {
22238 else switch (block.wantSafeTypes()) {
2217522239 true => .safety,
2217622240 false => .none,
2217722241 },
......@@ -23117,11 +23181,12 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2311723181 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
2311823182 const src = block.nodeOffset(extra.node);
2311923183 const operand_src = block.builtinCallArgSrc(extra.node, 0);
23120 const base_dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast");
23184 const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast");
2312123185 const operand = try sema.resolveInst(extra.rhs);
23122 const base_operand_ty = sema.typeOf(operand);
23123 const dest_tag = base_dest_ty.zigTypeTag(zcu);
23124 const operand_tag = base_operand_ty.zigTypeTag(zcu);
23186 const operand_ty = sema.typeOf(operand);
23187
23188 const dest_tag = dest_ty.zigTypeTag(zcu);
23189 const operand_tag = operand_ty.zigTypeTag(zcu);
2312523190
2312623191 if (dest_tag != .error_set and dest_tag != .error_union) {
2312723192 return sema.fail(block, src, "expected error set or error union type, found '{s}'", .{@tagName(dest_tag)});
......@@ -23133,107 +23198,133 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2313323198 return sema.fail(block, src, "cannot cast an error union type to error set", .{});
2313423199 }
2313523200 if (dest_tag == .error_union and operand_tag == .error_union and
23136 base_dest_ty.errorUnionPayload(zcu).toIntern() != base_operand_ty.errorUnionPayload(zcu).toIntern())
23201 dest_ty.errorUnionPayload(zcu).toIntern() != operand_ty.errorUnionPayload(zcu).toIntern())
2313723202 {
2313823203 return sema.failWithOwnedErrorMsg(block, msg: {
2313923204 const msg = try sema.errMsg(src, "payload types of error unions must match", .{});
2314023205 errdefer msg.destroy(sema.gpa);
23141 const dest_ty = base_dest_ty.errorUnionPayload(zcu);
23142 const operand_ty = base_operand_ty.errorUnionPayload(zcu);
23143 try sema.errNote(src, msg, "destination payload is '{}'", .{dest_ty.fmt(pt)});
23144 try sema.errNote(src, msg, "operand payload is '{}'", .{operand_ty.fmt(pt)});
23206 const dest_payload_ty = dest_ty.errorUnionPayload(zcu);
23207 const operand_payload_ty = operand_ty.errorUnionPayload(zcu);
23208 try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)});
23209 try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)});
2314523210 try addDeclaredHereNote(sema, msg, dest_ty);
2314623211 try addDeclaredHereNote(sema, msg, operand_ty);
2314723212 break :msg msg;
2314823213 });
2314923214 }
23150 const dest_ty = if (dest_tag == .error_union) base_dest_ty.errorUnionSet(zcu) else base_dest_ty;
23151 const operand_ty = if (operand_tag == .error_union) base_operand_ty.errorUnionSet(zcu) else base_operand_ty;
23152
23153 // operand must be defined since it can be an invalid error value
23154 const maybe_operand_val = try sema.resolveDefinedValue(block, operand_src, operand);
23215 const dest_err_ty = switch (dest_tag) {
23216 .error_union => dest_ty.errorUnionSet(zcu),
23217 .error_set => dest_ty,
23218 else => unreachable,
23219 };
23220 const operand_err_ty = switch (operand_tag) {
23221 .error_union => operand_ty.errorUnionSet(zcu),
23222 .error_set => operand_ty,
23223 else => unreachable,
23224 };
2315523225
2315623226 const disjoint = disjoint: {
2315723227 // Try avoiding resolving inferred error sets if we can
23158 if (!dest_ty.isAnyError(zcu) and dest_ty.errorSetIsEmpty(zcu)) break :disjoint true;
23159 if (!operand_ty.isAnyError(zcu) and operand_ty.errorSetIsEmpty(zcu)) break :disjoint true;
23160 if (dest_ty.isAnyError(zcu)) break :disjoint false;
23161 if (operand_ty.isAnyError(zcu)) break :disjoint false;
23162 const dest_err_names = dest_ty.errorSetNames(zcu);
23228 if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;
23229 if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;
23230 if (dest_err_ty.isAnyError(zcu)) break :disjoint false;
23231 if (operand_err_ty.isAnyError(zcu)) break :disjoint false;
23232 const dest_err_names = dest_err_ty.errorSetNames(zcu);
2316323233 for (0..dest_err_names.len) |dest_err_index| {
23164 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
23234 if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
2316523235 break :disjoint false;
2316623236 }
2316723237
23168 if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and
23169 !ip.isInferredErrorSetType(operand_ty.toIntern()))
23238 if (!ip.isInferredErrorSetType(dest_err_ty.toIntern()) and
23239 !ip.isInferredErrorSetType(operand_err_ty.toIntern()))
2317023240 {
2317123241 break :disjoint true;
2317223242 }
2317323243
23174 _ = try sema.resolveInferredErrorSetTy(block, src, dest_ty.toIntern());
23175 _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty.toIntern());
23244 _ = try sema.resolveInferredErrorSetTy(block, src, dest_err_ty.toIntern());
23245 _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_err_ty.toIntern());
2317623246 for (0..dest_err_names.len) |dest_err_index| {
23177 if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
23247 if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
2317823248 break :disjoint false;
2317923249 }
2318023250
2318123251 break :disjoint true;
2318223252 };
23183 if (disjoint and dest_tag != .error_union) {
23253 if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {
2318423254 return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{
23185 operand_ty.fmt(pt), dest_ty.fmt(pt),
23255 operand_err_ty.fmt(pt), dest_err_ty.fmt(pt),
2318623256 });
2318723257 }
2318823258
23189 if (maybe_operand_val) |val| {
23190 if (!dest_ty.isAnyError(zcu)) check: {
23191 const operand_val = zcu.intern_pool.indexToKey(val.toIntern());
23192 var error_name: InternPool.NullTerminatedString = undefined;
23193 if (operand_tag == .error_union) {
23194 if (operand_val.error_union.val != .err_name) break :check;
23195 error_name = operand_val.error_union.val.err_name;
23196 } else {
23197 error_name = operand_val.err.name;
23198 }
23199 if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) {
23200 return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{
23201 error_name.fmt(ip), dest_ty.fmt(pt),
23202 });
23203 }
23259 // operand must be defined since it can be an invalid error value
23260 if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
23261 const err_name: InternPool.NullTerminatedString = switch (operand_tag) {
23262 .error_set => ip.indexToKey(operand_val.toIntern()).err.name,
23263 .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) {
23264 .err_name => |name| name,
23265 .payload => |payload_val| {
23266 assert(dest_tag == .error_union); // should be guaranteed from the type checks above
23267 return sema.coerce(block, dest_ty, Air.internedToRef(payload_val), operand_src);
23268 },
23269 },
23270 else => unreachable,
23271 };
23272
23273 if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) {
23274 return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{
23275 err_name.fmt(ip), dest_err_ty.fmt(pt),
23276 });
2320423277 }
2320523278
23206 return Air.internedToRef((try pt.getCoerced(val, base_dest_ty)).toIntern());
23279 return Air.internedToRef(try pt.intern(switch (dest_tag) {
23280 .error_set => .{ .err = .{
23281 .ty = dest_ty.toIntern(),
23282 .name = err_name,
23283 } },
23284 .error_union => .{ .error_union = .{
23285 .ty = dest_ty.toIntern(),
23286 .val = .{ .err_name = err_name },
23287 } },
23288 else => unreachable,
23289 }));
2320723290 }
2320823291
23209 try sema.requireRuntimeBlock(block, src, operand_src);
2321023292 const err_int_ty = try pt.errorIntType();
23211 if (block.wantSafety() and !dest_ty.isAnyError(zcu) and
23212 dest_ty.toIntern() != .adhoc_inferred_error_set_type and
23293 if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and
23294 dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and
2321323295 zcu.backendSupportsFeature(.error_set_has_value))
2321423296 {
23215 if (dest_tag == .error_union) {
23216 const err_code = try sema.analyzeErrUnionCode(block, operand_src, operand);
23217 const err_int = try block.addBitCast(err_int_ty, err_code);
23218 const zero_err = try pt.intRef(try pt.errorIntType(), 0);
23297 const err_code_inst = switch (operand_tag) {
23298 .error_set => operand,
23299 .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand),
23300 else => unreachable,
23301 };
23302 const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst);
2321923303
23220 const is_zero = try block.addBinOp(.cmp_eq, err_int, zero_err);
23304 if (dest_tag == .error_union) {
23305 const zero_err = try pt.intRef(err_int_ty, 0);
23306 const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err);
2322123307 if (disjoint) {
2322223308 // Error must be zero.
2322323309 try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code);
2322423310 } else {
2322523311 // Error must be in destination set or zero.
23226 const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code);
23312 const has_value = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst);
2322723313 const ok = try block.addBinOp(.bool_or, has_value, is_zero);
2322823314 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
2322923315 }
2323023316 } else {
23231 const err_int_inst = try block.addBitCast(err_int_ty, operand);
23232 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
23317 const ok = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst);
2323323318 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
2323423319 }
2323523320 }
23236 return block.addBitCast(base_dest_ty, operand);
23321
23322 if (operand_tag == .error_set and dest_tag == .error_union) {
23323 const err_val = try block.addBitCast(dest_err_ty, operand);
23324 return block.addTyOp(.wrap_errunion_err, dest_ty, err_val);
23325 } else {
23326 return block.addBitCast(dest_ty, operand);
23327 }
2323723328}
2323823329
2323923330fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
......@@ -28952,6 +29043,7 @@ fn elemValArray(
2895229043 }
2895329044
2895429045 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
29046 try sema.validateRuntimeValue(block, array_src, array);
2895529047
2895629048 if (oob_safety and block.wantSafety()) {
2895729049 // Runtime check is only needed if unable to comptime check.
......@@ -29016,6 +29108,7 @@ fn elemPtrArray(
2901629108
2901729109 if (!init) {
2901829110 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src);
29111 try sema.validateRuntimeValue(block, array_ptr_src, array_ptr);
2901929112 }
2902029113
2902129114 // Runtime check is only needed if unable to comptime check.
......@@ -29073,6 +29166,7 @@ fn elemValSlice(
2907329166 }
2907429167
2907529168 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
29169 try sema.validateRuntimeValue(block, slice_src, slice);
2907629170
2907729171 if (oob_safety and block.wantSafety()) {
2907829172 const len_inst = if (maybe_slice_val) |slice_val|
......@@ -29129,6 +29223,7 @@ fn elemPtrSlice(
2912929223 }
2913029224
2913129225 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src);
29226 try sema.validateRuntimeValue(block, slice_src, slice);
2913229227
2913329228 if (oob_safety and block.wantSafety()) {
2913429229 const len_inst = len: {
......@@ -33889,6 +33984,17 @@ fn resolvePeerTypes(
3388933984 else => {},
3389033985 }
3389133986
33987 // Fast path: check if everything has the same type to bypass the main PTR logic.
33988 same_type: {
33989 const ty = sema.typeOf(instructions[0]);
33990 for (instructions[1..]) |inst| {
33991 if (sema.typeOf(inst).toIntern() != ty.toIntern()) {
33992 break :same_type;
33993 }
33994 }
33995 return ty;
33996 }
33997
3389233998 const peer_tys = try sema.arena.alloc(?Type, instructions.len);
3389333999 const peer_vals = try sema.arena.alloc(?Value, instructions.len);
3389434000
......@@ -34562,14 +34668,14 @@ fn resolvePeerTypesInner(
3456234668 }
3456334669 // Clear existing sentinel
3456434670 ptr_info.sentinel = .none;
34565 switch (ip.indexToKey(ptr_info.child)) {
34671 if (ptr_info.flags.size == .one) switch (ip.indexToKey(ptr_info.child)) {
3456634672 .array_type => |array_type| ptr_info.child = (try pt.arrayType(.{
3456734673 .len = array_type.len,
3456834674 .child = array_type.child,
3456934675 .sentinel = .none,
3457034676 })).toIntern(),
3457134677 else => {},
34572 }
34678 };
3457334679 }
3457434680
3457534681 opt_ptr_info = ptr_info;
src/Zcu.zig+2
......@@ -181,6 +181,8 @@ analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
181181/// Allocated into `gpa`.
182182resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null,
183183
184skip_analysis_errors: bool = false,
185
184186stage1_flags: packed struct {
185187 have_winmain: bool = false,
186188 have_wwinmain: bool = false,
src/print_zir.zig+1
......@@ -208,6 +208,7 @@ const Writer = struct {
208208 .anyframe_type,
209209 .bit_not,
210210 .bool_not,
211 .slice_sentinel_ty,
211212 .negate,
212213 .negate_wrap,
213214 .load,
test/behavior/cast.zig+16
......@@ -2649,3 +2649,19 @@ test "bitcast vector" {
26492649 const bigsum: u32x8 = @bitCast(zerox32);
26502650 try std.testing.expectEqual(0, @reduce(.Add, bigsum));
26512651}
2652
2653test "peer type resolution: slice of sentinel-terminated array" {
2654 var f: bool = undefined;
2655 f = false;
2656
2657 const a: [][2:0]u8 = &.{};
2658 const b: []const [2:0]u8 = &.{.{ 10, 20 }};
2659
2660 const result = if (f) a else b;
2661
2662 comptime assert(@TypeOf(result) == []const [2:0]u8);
2663 try expect(result.len == 1);
2664 try expect(result[0].len == 2);
2665 try expect(result[0][0] == 10);
2666 try expect(result[0][1] == 20);
2667}
test/behavior/error.zig+29-3
......@@ -1060,9 +1060,24 @@ test "errorCast to adhoc inferred error set" {
10601060 try std.testing.expect((try S.baz()) == 1234);
10611061}
10621062
1063test "errorCast from error sets to error unions" {
1064 const err_union: Set1!void = @errorCast(error.A);
1065 try expectError(error.A, err_union);
1063test "@errorCast from error set to error union" {
1064 const S = struct {
1065 fn doTheTest(set: error{ A, B }) error{A}!i32 {
1066 return @errorCast(set);
1067 }
1068 };
1069 try expectError(error.A, S.doTheTest(error.A));
1070 try expectError(error.A, comptime S.doTheTest(error.A));
1071}
1072
1073test "@errorCast from error union to error union" {
1074 const S = struct {
1075 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
1076 return @errorCast(set);
1077 }
1078 };
1079 try expectError(error.A, S.doTheTest(error.A));
1080 try expectError(error.A, comptime S.doTheTest(error.A));
10661081}
10671082
10681083test "result location initialization of error union with OPV payload" {
......@@ -1100,3 +1115,14 @@ test "return error union with i65" {
11001115fn add(x: i65, y: i65) anyerror!i65 {
11011116 return x + y;
11021117}
1118
1119test "compare error union to error set" {
1120 const S = struct {
1121 fn doTheTest(val: error{Foo}!i32) !void {
1122 if (error.Foo == val) return error.Unexpected;
1123 if (val == error.Foo) return error.Unexpected;
1124 }
1125 };
1126 try S.doTheTest(0);
1127 try comptime S.doTheTest(0);
1128}
test/behavior/eval.zig+11
......@@ -1751,3 +1751,14 @@ test "comptime labeled block implicit exit" {
17511751 };
17521752 comptime assert(result == {});
17531753}
1754
1755test "comptime block has intermediate runtime-known values" {
1756 const arr: [2]u8 = .{ 1, 2 };
1757
1758 var idx: usize = undefined;
1759 idx = 0;
1760
1761 comptime {
1762 _ = arr[idx];
1763 }
1764}
test/behavior/fn.zig+17
......@@ -711,3 +711,20 @@ test "inline call propagates comptime-known argument to generic parameter and re
711711 try expect(a1 == 12340);
712712 try expect(b1 == 12340);
713713}
714
715test "inline function return type is evaluated at comptime" {
716 const S = struct {
717 inline fn assertComptimeAndRet(x: anytype) @TypeOf(x) {
718 if (!@inComptime()) comptime unreachable;
719 return x;
720 }
721
722 inline fn foo(val: anytype) assertComptimeAndRet(u16) {
723 return val;
724 }
725 };
726
727 const result = S.foo(123);
728 comptime assert(@TypeOf(result) == u16);
729 try expect(result == 123);
730}
test/behavior/generics.zig+16
......@@ -589,3 +589,19 @@ comptime {
589589 // should override the result of the previous analysis.
590590 for (0..2) |_| _ = fn (void) void;
591591}
592
593test "generic parameter resolves to comptime-only type but is not marked comptime" {
594 const S = struct {
595 fn foo(comptime T: type, rt_false: bool, func: fn (T) void) T {
596 if (rt_false) _ = foo(T, rt_false, func);
597 return 123;
598 }
599 fn bar(_: u8) void {}
600 };
601
602 const rt_result = S.foo(u8, false, S.bar);
603 try expect(rt_result == 123);
604
605 const ct_result = comptime S.foo(u8, false, S.bar);
606 comptime std.debug.assert(ct_result == 123);
607}
test/behavior/slice.zig+13
......@@ -1037,3 +1037,16 @@ test "peer slices keep abi alignment with empty struct" {
10371037 comptime assert(@TypeOf(slice) == []const u32);
10381038 try expect(slice.len == 0);
10391039}
1040
1041test "sentinel expression in slice operation has result type" {
1042 const sentinel = std.math.maxInt(u16);
1043
1044 const arr: [3]u16 = .{ 1, 2, sentinel };
1045 const slice = arr[0..2 :@intCast(sentinel)];
1046
1047 comptime assert(@TypeOf(slice) == *const [2:sentinel]u16);
1048 comptime assert(slice[2] == sentinel);
1049 comptime assert(slice.len == 2);
1050 comptime assert(slice[0] == 1);
1051 comptime assert(slice[1] == 2);
1052}
test/behavior/type_info.zig+9
......@@ -675,3 +675,12 @@ test "@typeInfo only contains pub decls" {
675675 try std.testing.expectEqualStrings("Enum", decls[0].name);
676676 try std.testing.expectEqualStrings("Struct", decls[1].name);
677677}
678
679test "@typeInfo function with generic return type and inferred error set" {
680 const S = struct {
681 fn testFn(comptime T: type) !T {}
682 };
683
684 const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type;
685 comptime assert(ret_ty == null);
686}
test/behavior/union.zig+16
......@@ -2322,3 +2322,19 @@ test "assign global tagged union" {
23222322 try expect(U.global == .b);
23232323 try expect(U.global.b == 123456);
23242324}
2325
2326test "set mutable union by switching on same union" {
2327 const U = union(enum) {
2328 foo,
2329 bar: usize,
2330 };
2331
2332 var val: U = .foo;
2333 val = switch (val) {
2334 .foo => .{ .bar = 2 },
2335 .bar => .foo,
2336 };
2337
2338 try expect(val == .bar);
2339 try expect(val.bar == 2);
2340}
test/cases/compile_errors/for_comptime_array_pointer.zig created+12
......@@ -0,0 +1,12 @@
1export fn foo() void {
2 comptime var elems: [3]u32 = undefined;
3 for (&elems) |*elem| {
4 _ = elem;
5 }
6}
7
8// error
9//
10// :3:10: error: runtime value contains reference to comptime var
11// :3:10: note: comptime var pointers are not available at runtime
12// :2:34: note: 'runtime_value' points to comptime var declared here
test/cases/compile_errors/struct_depends_on_itself_via_non_initial_field.zig created+12
......@@ -0,0 +1,12 @@
1const A = struct {
2 a: u8,
3 bytes: [@sizeOf(A)]u8,
4};
5
6comptime {
7 _ = A;
8}
9
10// error
11//
12// :1:11: error: struct 'tmp.A' depends on itself
test/cases/compile_errors/tagName_on_undef_enum_literal.zig created+8
......@@ -0,0 +1,8 @@
1comptime {
2 const undef: @Type(.enum_literal) = undefined;
3 _ = @tagName(undef);
4}
5
6// error
7//
8// :3:18: error: use of undefined value here causes undefined behavior
test/incremental/analysis_error_and_syntax_error created+42
......@@ -0,0 +1,42 @@
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
7pub fn main() !void {
8 @compileError("uh oh");
9}
10#expect_error=main.zig:2:5: error: uh oh
11
12#update=add parse error
13#file=main.zig
14pub fn main() !void {
15 @compileError("uh oh");
16#expect_error=main.zig:3:1: error: expected statement, found 'EOF'
17
18#update=fix parse error
19#file=main.zig
20pub fn main() !void {
21 @compileError("uh oh");
22}
23#expect_error=main.zig:2:5: error: uh oh
24
25#update=add parse error again
26#file=main.zig
27pub fn main() !void {
28 @compileError("uh oh");
29#expect_error=main.zig:3:1: error: expected statement, found 'EOF'
30
31#update=comment @compileError call
32#file=main.zig
33pub fn main() !void {
34 //@compileError("uh oh");
35#expect_error=main.zig:3:1: error: expected statement, found 'EOF'
36
37#update=fix parse error again
38#file=main.zig
39pub fn main() !void {
40 //@compileError("uh oh");
41}
42#expect_stdout=""