authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-12 20:37:28+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:12+00:00
log986a4f1445e3ed1a6227a24d78b2154239ccdb31
tree488f38252e6285432dedd3b00e9a5c5fa3c71ffd
parentb27c56fe5087872800f6b340ec3d1fc219d0d77b
signaturelock-open Commit is signed but in an unrecognized format.

Sema: fix illegal comparison to undefined


1 files changed, 24 insertions(+), 28 deletions(-)

src/Sema.zig+24-28
...@@ -10374,7 +10374,7 @@ fn analyzeSwitchBlock(...@@ -10374,7 +10374,7 @@ fn analyzeSwitchBlock(
10374 assert(case.range_infos.len == 0);10374 assert(case.range_infos.len == 0);
10375 for (case.item_infos, item_refs) |item_info, item_ref| {10375 for (case.item_infos, item_refs) |item_info, item_ref| {
10376 if (item_info.bodyLen()) |body_len| extra_index += body_len;10376 if (item_info.bodyLen()) |body_len| extra_index += body_len;
10377 if (sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, false, true, prong_info.is_comptime_unreach)) {10377 if (sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, false, true, prong_info.is_comptime_unreach)) {
10378 break :skip_case;10378 break :skip_case;
10379 }10379 }
10380 }10380 }
...@@ -10390,7 +10390,7 @@ fn analyzeSwitchBlock(...@@ -10390,7 +10390,7 @@ fn analyzeSwitchBlock(
10390 unreachable; // malformed validated switch10390 unreachable; // malformed validated switch
10391 };10391 };
1039210392
10393 const analyze_body = sema.wantSwitchProngBodyAnalysis(block, .fromValue(item_opv), operand_ty, union_originally, err_set, false);10393 const analyze_body = sema.wantSwitchProngBodyAnalysis(.fromValue(item_opv), operand_ty, union_originally, err_set, false);
10394 if (!analyze_body) return .unreachable_value;10394 if (!analyze_body) return .unreachable_value;
1039510395
10396 if (!(err_set and10396 if (!(err_set and
...@@ -10648,7 +10648,7 @@ fn finishSwitchBr(...@@ -10648,7 +10648,7 @@ fn finishSwitchBr(
10648 if (item_ref == .none) is_under_prong = true;10648 if (item_ref == .none) is_under_prong = true;
10649 if (item_info.bodyLen()) |body_len| extra_index += body_len;10649 if (item_info.bodyLen()) |body_len| extra_index += body_len;
1065010650
10651 const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach);10651 const analyze_body = sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach);
10652 if (analyze_body) any_analyze_body = true;10652 if (analyze_body) any_analyze_body = true;
1065310653
10654 if (prong_info.is_inline) {10654 if (prong_info.is_inline) {
...@@ -10708,8 +10708,8 @@ fn finishSwitchBr(...@@ -10708,8 +10708,8 @@ fn finishSwitchBr(
10708 any_analyze_body = true; // always an integer range, always needs analysis10708 any_analyze_body = true; // always an integer range, always needs analysis
1070910709
10710 if (prong_info.is_inline) {10710 if (prong_info.is_inline) {
10711 var item = sema.resolveConstDefinedValue(block, .unneeded, range_ref[0], undefined) catch unreachable;10711 var item = sema.resolveValue(range_ref[0]).?;
10712 const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_ref[1], undefined) catch unreachable;10712 const item_last = sema.resolveValue(range_ref[1]).?;
1071310713
10714 if (item.getUnsignedInt(zcu)) |first_int| {10714 if (item.getUnsignedInt(zcu)) |first_int| {
10715 if (item_last.getUnsignedInt(zcu)) |last_int| {10715 if (item_last.getUnsignedInt(zcu)) |last_int| {
...@@ -10887,7 +10887,7 @@ fn finishSwitchBr(...@@ -10887,7 +10887,7 @@ fn finishSwitchBr(
1088710887
10888 const item_ref: Air.Inst.Ref = .fromValue(item_val);10888 const item_ref: Air.Inst.Ref = .fromValue(item_val);
1088910889
10890 const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, false);10890 const analyze_body = sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, union_originally, err_set, false);
1089110891
10892 if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src);10892 if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src);
10893 emit_bb = true;10893 emit_bb = true;
...@@ -11820,7 +11820,7 @@ fn resolveSwitchBlock(...@@ -11820,7 +11820,7 @@ fn resolveSwitchBlock(
11820 };11820 };
11821 continue;11821 continue;
11822 }11822 }
11823 const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable;11823 const item_val = sema.resolveValue(item_ref).?;
11824 if (cond_val.eql(item_val, item_ty, zcu)) {11824 if (cond_val.eql(item_val, item_ty, zcu)) {
11825 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);11825 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);
11826 if (union_originally and operand_ty.unionFieldType(item_val, zcu).?.isNoReturn(zcu)) {11826 if (union_originally and operand_ty.unionFieldType(item_val, zcu).?.isNoReturn(zcu)) {
...@@ -11853,8 +11853,8 @@ fn resolveSwitchBlock(...@@ -11853,8 +11853,8 @@ fn resolveSwitchBlock(
11853 }11853 }
11854 }11854 }
11855 for (range_refs) |range_ref| {11855 for (range_refs) |range_ref| {
11856 const first_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_ref[0], undefined) catch unreachable;11856 const first_val = sema.resolveValue(range_ref[0]).?;
11857 const last_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_ref[1], undefined) catch unreachable;11857 const last_val = sema.resolveValue(range_ref[1]).?;
11858 if ((try sema.compareAll(cond_val, .gte, first_val, item_ty)) and11858 if ((try sema.compareAll(cond_val, .gte, first_val, item_ty)) and
11859 (try sema.compareAll(cond_val, .lte, last_val, item_ty)))11859 (try sema.compareAll(cond_val, .lte, last_val, item_ty)))
11860 {11860 {
...@@ -12063,7 +12063,6 @@ fn resolveSwitchProng(...@@ -12063,7 +12063,6 @@ fn resolveSwitchProng(
1206312063
12064fn wantSwitchProngBodyAnalysis(12064fn wantSwitchProngBodyAnalysis(
12065 sema: *Sema,12065 sema: *Sema,
12066 block: *Block,
12067 item_ref: Air.Inst.Ref,12066 item_ref: Air.Inst.Ref,
12068 operand_ty: Type,12067 operand_ty: Type,
12069 union_originally: bool,12068 union_originally: bool,
...@@ -12072,12 +12071,12 @@ fn wantSwitchProngBodyAnalysis(...@@ -12072,12 +12071,12 @@ fn wantSwitchProngBodyAnalysis(
12072) bool {12071) bool {
12073 const zcu = sema.pt.zcu;12072 const zcu = sema.pt.zcu;
12074 if (union_originally) {12073 if (union_originally) {
12075 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;12074 const item_val = sema.resolveValue(item_ref).?;
12076 const field_ty = operand_ty.unionFieldType(item_val, zcu).?;12075 const field_ty = operand_ty.unionFieldType(item_val, zcu).?;
12077 if (field_ty.isNoReturn(zcu)) return false;12076 if (field_ty.isNoReturn(zcu)) return false;
12078 }12077 }
12079 if (err_set and prong_is_comptime_unreach) {12078 if (err_set and prong_is_comptime_unreach) {
12080 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;12079 const item_val = sema.resolveValue(item_ref).?;
12081 const err_name = item_val.getErrorName(zcu).unwrap().?;12080 const err_name = item_val.getErrorName(zcu).unwrap().?;
12082 if (!operand_ty.errorSetHasField(err_name, zcu)) return false;12081 if (!operand_ty.errorSetHasField(err_name, zcu)) return false;
12083 }12082 }
...@@ -12252,7 +12251,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12252,7 +12251,7 @@ fn analyzeSwitchPayloadCapture(
12252 const switch_node_offset = operand_src.offset.node_offset_switch_operand;12251 const switch_node_offset = operand_src.offset.node_offset_switch_operand;
1225312252
12254 if (kind == .inline_ref) {12253 if (kind == .inline_ref) {
12255 const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, kind.inline_ref, undefined) catch unreachable;12254 const item_val = sema.resolveValue(kind.inline_ref).?;
12256 if (operand_ty.zigTypeTag(zcu) == .@"union") {12255 if (operand_ty.zigTypeTag(zcu) == .@"union") {
12257 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);12256 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);
12258 const union_obj = zcu.typeToUnion(operand_ty).?;12257 const union_obj = zcu.typeToUnion(operand_ty).?;
...@@ -12303,14 +12302,14 @@ fn analyzeSwitchPayloadCapture(...@@ -12303,14 +12302,14 @@ fn analyzeSwitchPayloadCapture(
12303 const case_vals = kind.item_refs;12302 const case_vals = kind.item_refs;
1230412303
12305 const union_obj = zcu.typeToUnion(operand_ty).?;12304 const union_obj = zcu.typeToUnion(operand_ty).?;
12306 const first_item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;12305 const first_item_val = sema.resolveValue(case_vals[0]).?;
1230712306
12308 const first_field_index: u32 = zcu.unionTagFieldIndex(union_obj, first_item_val).?;12307 const first_field_index: u32 = zcu.unionTagFieldIndex(union_obj, first_item_val).?;
12309 const first_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[first_field_index]);12308 const first_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[first_field_index]);
1231012309
12311 const field_indices = try sema.arena.alloc(u32, case_vals.len);12310 const field_indices = try sema.arena.alloc(u32, case_vals.len);
12312 for (case_vals, field_indices) |item, *field_idx| {12311 for (case_vals, field_indices) |item, *field_idx| {
12313 const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, item, undefined) catch unreachable;12312 const item_val = sema.resolveValue(item).?;
12314 field_idx.* = zcu.unionTagFieldIndex(union_obj, item_val).?;12313 field_idx.* = zcu.unionTagFieldIndex(union_obj, item_val).?;
12315 }12314 }
1231612315
...@@ -12592,7 +12591,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12592,7 +12591,7 @@ fn analyzeSwitchPayloadCapture(
1259212591
12593 const case_vals = kind.item_refs;12592 const case_vals = kind.item_refs;
12594 if (case_vals.len == 1) {12593 if (case_vals.len == 1) {
12595 const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;12594 const item_val = sema.resolveValue(case_vals[0]).?;
12596 const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);12595 const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);
12597 return sema.bitCast(case_block, item_ty, .fromValue(item_val), operand_src, null);12596 return sema.bitCast(case_block, item_ty, .fromValue(item_val), operand_src, null);
12598 }12597 }
...@@ -12600,7 +12599,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12600,7 +12599,7 @@ fn analyzeSwitchPayloadCapture(
12600 var names: InferredErrorSet.NameMap = .{};12599 var names: InferredErrorSet.NameMap = .{};
12601 try names.ensureUnusedCapacity(sema.arena, case_vals.len);12600 try names.ensureUnusedCapacity(sema.arena, case_vals.len);
12602 for (case_vals) |err| {12601 for (case_vals) |err| {
12603 const err_val = sema.resolveConstDefinedValue(case_block, .unneeded, err, undefined) catch unreachable;12602 const err_val = sema.resolveValue(err).?;
12604 names.putAssumeCapacityNoClobber(err_val.getErrorName(zcu).unwrap().?, {});12603 names.putAssumeCapacityNoClobber(err_val.getErrorName(zcu).unwrap().?, {});
12605 }12604 }
12606 const error_ty = try pt.errorSetFromUnsortedNames(names.keys());12605 const error_ty = try pt.errorSetFromUnsortedNames(names.keys());
...@@ -13731,26 +13730,24 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13731,26 +13730,24 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13731 const lhs_elem_i = elem_i;13730 const lhs_elem_i = elem_i;
13732 const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null;13731 const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null;
13733 const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i);13732 const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i);
13734 const elem_val_inst = Air.internedToRef(elem_val.toIntern());
13735 const operand_src = block.src(.{ .array_cat_lhs = .{13733 const operand_src = block.src(.{ .array_cat_lhs = .{
13736 .array_cat_offset = inst_data.src_node,13734 .array_cat_offset = inst_data.src_node,
13737 .elem_index = elem_i,13735 .elem_index = elem_i,
13738 } });13736 } });
13739 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src);13737 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, .fromValue(elem_val), operand_src);
13740 const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined);13738 const coerced_elem_val = sema.resolveValue(coerced_elem_val_inst).?;
13741 element_vals[elem_i] = coerced_elem_val.toIntern();13739 element_vals[elem_i] = coerced_elem_val.toIntern();
13742 }13740 }
13743 while (elem_i < result_len) : (elem_i += 1) {13741 while (elem_i < result_len) : (elem_i += 1) {
13744 const rhs_elem_i = elem_i - lhs_len;13742 const rhs_elem_i = elem_i - lhs_len;
13745 const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null;13743 const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null;
13746 const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i);13744 const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i);
13747 const elem_val_inst = Air.internedToRef(elem_val.toIntern());
13748 const operand_src = block.src(.{ .array_cat_rhs = .{13745 const operand_src = block.src(.{ .array_cat_rhs = .{
13749 .array_cat_offset = inst_data.src_node,13746 .array_cat_offset = inst_data.src_node,
13750 .elem_index = @intCast(rhs_elem_i),13747 .elem_index = @intCast(rhs_elem_i),
13751 } });13748 } });
13752 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src);13749 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, .fromValue(elem_val), operand_src);
13753 const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined);13750 const coerced_elem_val = sema.resolveValue(coerced_elem_val_inst).?;
13754 element_vals[elem_i] = coerced_elem_val.toIntern();13751 element_vals[elem_i] = coerced_elem_val.toIntern();
13755 }13752 }
13756 return sema.addConstantMaybeRef(13753 return sema.addConstantMaybeRef(
...@@ -25886,7 +25883,6 @@ fn fieldPtr(...@@ -25886,7 +25883,6 @@ fn fieldPtr(
25886 }25883 }
25887 },25884 },
25888 .type => {25885 .type => {
25889 _ = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, object_ptr, undefined);
25890 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);25886 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
25891 const inner = if (is_pointer_to)25887 const inner = if (is_pointer_to)
25892 try sema.analyzeLoad(block, src, result, object_ptr_src)25888 try sema.analyzeLoad(block, src, result, object_ptr_src)
...@@ -27361,7 +27357,7 @@ fn coerceExtra(...@@ -27361,7 +27357,7 @@ fn coerceExtra(
2736127357
27362 // Function body to function pointer.27358 // Function body to function pointer.
27363 if (inst_ty.zigTypeTag(zcu) == .@"fn") {27359 if (inst_ty.zigTypeTag(zcu) == .@"fn") {
27364 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);27360 const fn_val = sema.resolveValue(inst).?;
27365 const fn_nav = switch (zcu.intern_pool.indexToKey(fn_val.toIntern())) {27361 const fn_nav = switch (zcu.intern_pool.indexToKey(fn_val.toIntern())) {
27366 .func => |f| f.owner_nav,27362 .func => |f| f.owner_nav,
27367 .@"extern" => |e| e.owner_nav,27363 .@"extern" => |e| e.owner_nav,
...@@ -27667,7 +27663,7 @@ fn coerceExtra(...@@ -27667,7 +27663,7 @@ fn coerceExtra(
27667 },27663 },
27668 .float, .comptime_float => switch (inst_ty.zigTypeTag(zcu)) {27664 .float, .comptime_float => switch (inst_ty.zigTypeTag(zcu)) {
27669 .comptime_float => {27665 .comptime_float => {
27670 const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);27666 const val = sema.resolveValue(inst).?;
27671 const result_val = try val.floatCast(dest_ty, pt);27667 const result_val = try val.floatCast(dest_ty, pt);
27672 return Air.internedToRef(result_val.toIntern());27668 return Air.internedToRef(result_val.toIntern());
27673 },27669 },
...@@ -27753,7 +27749,7 @@ fn coerceExtra(...@@ -27753,7 +27749,7 @@ fn coerceExtra(
27753 .@"enum" => switch (inst_ty.zigTypeTag(zcu)) {27749 .@"enum" => switch (inst_ty.zigTypeTag(zcu)) {
27754 .enum_literal => {27750 .enum_literal => {
27755 // enum literal to enum27751 // enum literal to enum
27756 const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);27752 const val = sema.resolveValue(inst).?;
27757 const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;27753 const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;
27758 const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {27754 const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {
27759 return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{27755 return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{
...@@ -28965,7 +28961,7 @@ fn coerceVarArgParam(...@@ -28965,7 +28961,7 @@ fn coerceVarArgParam(
28965 .{},28961 .{},
28966 ),28962 ),
28967 .@"fn" => fn_ptr: {28963 .@"fn" => fn_ptr: {
28968 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);28964 const fn_val = sema.resolveValue(inst).?;
28969 const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;28965 const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;
28970 break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav);28966 break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav);
28971 },28967 },