authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-01-12 19:59:47+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-01-13 06:03:07+01:00
log044ba3e0b020c317e8934d0d8271a512a9deeff8
tree1e15f54d75b54ace831b96066d90f8683a01208d
parent4fcf6507f9f96d1f341819dab89ded74cd3c7f7d

Sema: fix single-range switch prong capture (for real this time)

e2338edb47 didn't *quite* do it, the call sites of all switch prong related functions now have to do their part too and be a little more precise about what kind of prong they're currently analyzing. Also removes some unused/unnecessary stuff.

3 files changed, 70 insertions(+), 74 deletions(-)

lib/std/zig/Zir.zig-2
...@@ -3438,8 +3438,6 @@ pub const Inst = struct {...@@ -3438,8 +3438,6 @@ pub const Inst = struct {
3438 return if (item_info.kind == .body_len) item_info.data else null;3438 return if (item_info.kind == .body_len) item_info.data else null;
3439 }3439 }
3440 };3440 };
3441
3442 pub const Kind = enum { default, ref, err_union };
3443 };3441 };
34443442
3445 pub const ArrayInitRefTy = struct {3443 pub const ArrayInitRefTy = struct {
src/Sema.zig+63-71
...@@ -10747,8 +10747,6 @@ fn analyzeSwitchBlock(...@@ -10747,8 +10747,6 @@ fn analyzeSwitchBlock(
10747 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });10747 const operand_src = block.src(.{ .node_offset_switch_operand = src_node_offset });
1074810748
10749 const has_else = zir_switch.else_case != null;10749 const has_else = zir_switch.else_case != null;
10750 const has_under = zir_switch.has_under;
10751
10752 const else_case = validated_switch.else_case;10750 const else_case = validated_switch.else_case;
1075310751
10754 const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: {10752 const operand: SwitchOperand, const operand_ty: Type, const maybe_operand_opv: ?Value, const item_ty: Type = operand: {
...@@ -10813,11 +10811,6 @@ fn analyzeSwitchBlock(...@@ -10813,11 +10811,6 @@ fn analyzeSwitchBlock(
10813 .loop => |l| l.init_cond,10811 .loop => |l| l.init_cond,
10814 };10812 };
1081510813
10816 // We treat `else` and `_` the same, except if both are present.
10817 const else_is_named_only = has_else and has_under;
10818 const catch_all_case: CatchAllSwitchCase =
10819 if (has_under) .under else if (has_else) .@"else" else .none;
10820
10821 resolve_at_comptime: {10814 resolve_at_comptime: {
10822 // always runtime; evaluation in comptime scope uses `simple`10815 // always runtime; evaluation in comptime scope uses `simple`
10823 if (operand == .loop) break :resolve_at_comptime;10816 if (operand == .loop) break :resolve_at_comptime;
...@@ -10834,8 +10827,6 @@ fn analyzeSwitchBlock(...@@ -10834,8 +10827,6 @@ fn analyzeSwitchBlock(
10834 cur_operand,10827 cur_operand,
10835 raw_operand_ty,10828 raw_operand_ty,
10836 cur_cond_val,10829 cur_cond_val,
10837 catch_all_case,
10838 else_is_named_only,
10839 merges,10830 merges,
10840 switch_inst,10831 switch_inst,
10841 zir_switch,10832 zir_switch,
...@@ -10958,6 +10949,11 @@ fn analyzeSwitchBlock(...@@ -10958,6 +10949,11 @@ fn analyzeSwitchBlock(
10958 }10949 }
10959 },10950 },
10960 };10951 };
10952 const prong_kind: SwitchProngKind = kind: {
10953 if (is_inline) break :kind .{ .inline_ref = .fromValue(item_opv) };
10954 if (is_special) break :kind .special;
10955 break :kind .{ .item_refs = &.{.fromValue(item_opv)} };
10956 };
10961 break :payload_ref try sema.analyzeSwitchPayloadCapture(10957 break :payload_ref try sema.analyzeSwitchPayloadCapture(
10962 &case_block,10958 &case_block,
10963 operand,10959 operand,
...@@ -10970,8 +10966,7 @@ fn analyzeSwitchBlock(...@@ -10970,8 +10966,7 @@ fn analyzeSwitchBlock(
10970 .case_idx = index,10966 .case_idx = index,
10971 } }),10967 } }),
10972 capture == .by_ref,10968 capture == .by_ref,
10973 if (is_special) .special else .{ .item_refs = &.{.fromValue(item_opv)} },10969 prong_kind,
10974 if (is_inline) .fromValue(item_opv) else .none,
10975 validated_switch.else_err_ty,10970 validated_switch.else_err_ty,
10976 );10971 );
10977 },10972 },
...@@ -11094,8 +11089,6 @@ fn finishSwitchBr(...@@ -11094,8 +11089,6 @@ fn finishSwitchBr(
11094 const cond_dbg_node_index: Zir.Inst.Index = @enumFromInt(@intFromEnum(switch_inst) - 1);11089 const cond_dbg_node_index: Zir.Inst.Index = @enumFromInt(@intFromEnum(switch_inst) - 1);
1109511090
11096 const else_is_named_only = has_else and has_under;11091 const else_is_named_only = has_else and has_under;
11097 const catch_all_case: CatchAllSwitchCase =
11098 if (has_under) .under else if (has_else) .@"else" else .none;
1109911092
11100 const item_ty = switch (operand_ty.zigTypeTag(zcu)) {11093 const item_ty = switch (operand_ty.zigTypeTag(zcu)) {
11101 .@"union" => operand_ty.unionTagType(zcu).?,11094 .@"union" => operand_ty.unionTagType(zcu).?,
...@@ -11216,8 +11209,7 @@ fn finishSwitchBr(...@@ -11216,8 +11209,7 @@ fn finishSwitchBr(
11216 } }),11209 } }),
11217 prong_info.capture,11210 prong_info.capture,
11218 prong_info.has_tag_capture,11211 prong_info.has_tag_capture,
11219 item_ref,11212 .{ .inline_ref = item_ref },
11220 .{ .item_refs = &.{item_ref} },
11221 validated_switch.else_err_ty,11213 validated_switch.else_err_ty,
11222 switch_inst,11214 switch_inst,
11223 zir_switch,11215 zir_switch,
...@@ -11308,8 +11300,7 @@ fn finishSwitchBr(...@@ -11308,8 +11300,7 @@ fn finishSwitchBr(
11308 } }),11300 } }),
11309 prong_info.capture,11301 prong_info.capture,
11310 prong_info.has_tag_capture,11302 prong_info.has_tag_capture,
11311 item_ref,11303 .{ .inline_ref = item_ref },
11312 .has_ranges,
11313 validated_switch.else_err_ty,11304 validated_switch.else_err_ty,
11314 switch_inst,11305 switch_inst,
11315 zir_switch,11306 zir_switch,
...@@ -11333,6 +11324,9 @@ fn finishSwitchBr(...@@ -11333,6 +11324,9 @@ fn finishSwitchBr(
11333 if (prong_info.is_inline) continue; // handled above11324 if (prong_info.is_inline) continue; // handled above
1133411325
11335 if (is_under_prong) {11326 if (is_under_prong) {
11327 // We will handle this later. If there are any named items specified
11328 // along with the `_`, we don't have to actually emit any AIR for them
11329 // as they will be 'absorbed' by the `_` (the catch-all prong) anyway.
11336 under_prong = .{11330 under_prong = .{
11337 .index = case.index,11331 .index = case.index,
11338 .body = prong_body,11332 .body = prong_body,
...@@ -11359,8 +11353,7 @@ fn finishSwitchBr(...@@ -11359,8 +11353,7 @@ fn finishSwitchBr(
11359 } }),11353 } }),
11360 prong_info.capture,11354 prong_info.capture,
11361 prong_info.has_tag_capture,11355 prong_info.has_tag_capture,
11362 .none,11356 if (range_refs.len > 0) .has_ranges else .{ .item_refs = item_refs },
11363 .{ .item_refs = item_refs },
11364 validated_switch.else_err_ty,11357 validated_switch.else_err_ty,
11365 switch_inst,11358 switch_inst,
11366 zir_switch,11359 zir_switch,
...@@ -11385,7 +11378,7 @@ fn finishSwitchBr(...@@ -11385,7 +11378,7 @@ fn finishSwitchBr(
11385 }11378 }
1138611379
11387 const catch_all_extra: []const u32 = catch_all_extra: {11380 const catch_all_extra: []const u32 = catch_all_extra: {
11388 if (catch_all_case == .none and !case_block.wantSafety()) {11381 if (!has_else and !has_under and !case_block.wantSafety()) {
11389 try branch_hints.append(gpa, .none);11382 try branch_hints.append(gpa, .none);
11390 break :catch_all_extra &.{};11383 break :catch_all_extra &.{};
11391 }11384 }
...@@ -11445,8 +11438,7 @@ fn finishSwitchBr(...@@ -11445,8 +11438,7 @@ fn finishSwitchBr(
11445 } }),11438 } }),
11446 else_case.capture,11439 else_case.capture,
11447 else_case.has_tag_capture,11440 else_case.has_tag_capture,
11448 item_ref,11441 .{ .inline_ref = item_ref },
11449 .special,
11450 validated_switch.else_err_ty,11442 validated_switch.else_err_ty,
11451 switch_inst,11443 switch_inst,
11452 zir_switch,11444 zir_switch,
...@@ -11473,7 +11465,7 @@ fn finishSwitchBr(...@@ -11473,7 +11465,7 @@ fn finishSwitchBr(
11473 case_block.error_return_trace_index = child_block.error_return_trace_index;11465 case_block.error_return_trace_index = child_block.error_return_trace_index;
1147411466
11475 if (zcu.backendSupportsFeature(.is_named_enum_value) and11467 if (zcu.backendSupportsFeature(.is_named_enum_value) and
11476 catch_all_case != .none and block.wantSafety() and11468 (has_else or has_under) and block.wantSafety() and
11477 item_ty.zigTypeTag(zcu) == .@"enum" and11469 item_ty.zigTypeTag(zcu) == .@"enum" and
11478 (!operand_ty.isNonexhaustiveEnum(zcu) or union_originally))11470 (!operand_ty.isNonexhaustiveEnum(zcu) or union_originally))
11479 {11471 {
...@@ -11508,7 +11500,6 @@ fn finishSwitchBr(...@@ -11508,7 +11500,6 @@ fn finishSwitchBr(
11508 } }),11500 } }),
11509 else_case.capture,11501 else_case.capture,
11510 else_case.has_tag_capture,11502 else_case.has_tag_capture,
11511 .none,
11512 .special,11503 .special,
11513 validated_switch.else_err_ty,11504 validated_switch.else_err_ty,
11514 switch_inst,11505 switch_inst,
...@@ -11548,10 +11539,12 @@ fn finishSwitchBr(...@@ -11548,10 +11539,12 @@ fn finishSwitchBr(
11548 }11539 }
1154911540
11550 const analyze_catch_all_body = analyze_body: {11541 const analyze_catch_all_body = analyze_body: {
11551 switch (catch_all_case) {11542 if (has_under) {
11552 .none => break :analyze_body false, // we still may want a safety check!11543 break :analyze_body true; // can't be a union or an error set, never inlined
11553 .under => break :analyze_body true, // can't be a union anyway11544 } else if (has_else) {
11554 .@"else" => if (else_case.is_inline) break :analyze_body false,11545 if (else_case.is_inline) break :analyze_body false; // already handled above
11546 } else {
11547 break :analyze_body false; // we still may want a safety check!
11555 }11548 }
11556 if (union_originally) {11549 if (union_originally) {
11557 const union_obj = zcu.typeToUnion(operand_ty).?;11550 const union_obj = zcu.typeToUnion(operand_ty).?;
...@@ -11574,11 +11567,10 @@ fn finishSwitchBr(...@@ -11574,11 +11567,10 @@ fn finishSwitchBr(
1157411567
11575 const catch_all_hint = hint: {11568 const catch_all_hint = hint: {
11576 if (analyze_catch_all_body) {11569 if (analyze_catch_all_body) {
11577 const index, const body, const capture, const has_tag_capture = switch (catch_all_case) {11570 const index, const body, const capture, const has_tag_capture = if (under_prong) |under|
11578 .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture },11571 .{ under.index, under.body, under.capture, under.has_tag_capture }
11579 .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture },11572 else
11580 .none => unreachable,11573 .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture };
11581 };
11582 break :hint try sema.analyzeSwitchProng(11574 break :hint try sema.analyzeSwitchProng(
11583 &case_block,11575 &case_block,
11584 operand,11576 operand,
...@@ -11591,7 +11583,6 @@ fn finishSwitchBr(...@@ -11591,7 +11583,6 @@ fn finishSwitchBr(
11591 } }),11583 } }),
11592 capture,11584 capture,
11593 has_tag_capture,11585 has_tag_capture,
11594 .none,
11595 .special,11586 .special,
11596 validated_switch.else_err_ty,11587 validated_switch.else_err_ty,
11597 switch_inst,11588 switch_inst,
...@@ -12072,9 +12063,9 @@ fn validateSwitchBlock(...@@ -12072,9 +12063,9 @@ fn validateSwitchBlock(
12072 const msg = try sema.errMsg(12063 const msg = try sema.errMsg(
12073 operand_src,12064 operand_src,
12074 "ranges not allowed when switching on type '{f}'",12065 "ranges not allowed when switching on type '{f}'",
12075 .{operand_ty.fmt(sema.pt)},12066 .{operand_ty.fmt(pt)},
12076 );12067 );
12077 errdefer msg.destroy(sema.gpa);12068 errdefer msg.destroy(gpa);
12078 try sema.errNote(12069 try sema.errNote(
12079 range_src,12070 range_src,
12080 msg,12071 msg,
...@@ -12309,8 +12300,6 @@ fn resolveSwitchBlock(...@@ -12309,8 +12300,6 @@ fn resolveSwitchBlock(
12309 operand: SwitchOperand,12300 operand: SwitchOperand,
12310 raw_operand_ty: Type,12301 raw_operand_ty: Type,
12311 maybe_lazy_cond_val: Value,12302 maybe_lazy_cond_val: Value,
12312 catch_all_case: CatchAllSwitchCase,
12313 else_is_named_only: bool,
12314 merges: *Block.Merges,12303 merges: *Block.Merges,
12315 switch_inst: Zir.Inst.Index,12304 switch_inst: Zir.Inst.Index,
12316 zir_switch: *const Zir.UnwrappedSwitchBlock,12305 zir_switch: *const Zir.UnwrappedSwitchBlock,
...@@ -12377,6 +12366,11 @@ fn resolveSwitchBlock(...@@ -12377,6 +12366,11 @@ fn resolveSwitchBlock(
12377 // This prong should be unreachable!12366 // This prong should be unreachable!
12378 return .unreachable_value;12367 return .unreachable_value;
12379 }12368 }
12369 const prong_kind: SwitchProngKind = kind: {
12370 if (prong_info.is_inline) break :kind .{ .inline_ref = cond_ref };
12371 if (range_refs.len > 0) break :kind .has_ranges;
12372 break :kind .{ .item_refs = item_refs };
12373 };
12380 return sema.resolveSwitchProng(12374 return sema.resolveSwitchProng(
12381 block,12375 block,
12382 child_block,12376 child_block,
...@@ -12389,8 +12383,7 @@ fn resolveSwitchBlock(...@@ -12389,8 +12383,7 @@ fn resolveSwitchBlock(
12389 } }),12383 } }),
12390 prong_info.capture,12384 prong_info.capture,
12391 prong_info.has_tag_capture,12385 prong_info.has_tag_capture,
12392 if (prong_info.is_inline) cond_ref else .none,12386 prong_kind,
12393 .{ .item_refs = item_refs },
12394 validated_switch.else_err_ty,12387 validated_switch.else_err_ty,
12395 merges,12388 merges,
12396 switch_inst,12389 switch_inst,
...@@ -12404,6 +12397,10 @@ fn resolveSwitchBlock(...@@ -12404,6 +12397,10 @@ fn resolveSwitchBlock(
12404 if ((try sema.compareAll(cond_val, .gte, first_val, item_ty)) and12397 if ((try sema.compareAll(cond_val, .gte, first_val, item_ty)) and
12405 (try sema.compareAll(cond_val, .lte, last_val, item_ty)))12398 (try sema.compareAll(cond_val, .lte, last_val, item_ty)))
12406 {12399 {
12400 const prong_kind: SwitchProngKind = if (prong_info.is_inline)
12401 .{ .inline_ref = cond_ref }
12402 else
12403 .has_ranges;
12407 return sema.resolveSwitchProng(12404 return sema.resolveSwitchProng(
12408 block,12405 block,
12409 child_block,12406 child_block,
...@@ -12416,8 +12413,7 @@ fn resolveSwitchBlock(...@@ -12416,8 +12413,7 @@ fn resolveSwitchBlock(
12416 } }),12413 } }),
12417 prong_info.capture,12414 prong_info.capture,
12418 prong_info.has_tag_capture,12415 prong_info.has_tag_capture,
12419 if (prong_info.is_inline) cond_ref else .none,12416 prong_kind,
12420 .has_ranges,
12421 validated_switch.else_err_ty,12417 validated_switch.else_err_ty,
12422 merges,12418 merges,
12423 switch_inst,12419 switch_inst,
...@@ -12428,11 +12424,16 @@ fn resolveSwitchBlock(...@@ -12428,11 +12424,16 @@ fn resolveSwitchBlock(
12428 }12424 }
1242912425
12430 const else_case = validated_switch.else_case;12426 const else_case = validated_switch.else_case;
12427 const else_is_named_only = zir_switch.else_case != null and under_prong != null;
1243112428
12432 // named-only prong12429 // named-only prong
1243312430
12434 if (else_is_named_only and item_ty.enumTagFieldIndex(cond_val, zcu) != null) {12431 if (else_is_named_only and item_ty.enumTagFieldIndex(cond_val, zcu) != null) {
12435 assert(item_ty.isNonexhaustiveEnum(zcu));12432 assert(item_ty.isNonexhaustiveEnum(zcu));
12433 const prong_kind: SwitchProngKind = if (else_case.is_inline)
12434 .{ .inline_ref = cond_ref }
12435 else
12436 .special;
12436 return sema.resolveSwitchProng(12437 return sema.resolveSwitchProng(
12437 block,12438 block,
12438 child_block,12439 child_block,
...@@ -12445,8 +12446,7 @@ fn resolveSwitchBlock(...@@ -12445,8 +12446,7 @@ fn resolveSwitchBlock(
12445 } }),12446 } }),
12446 else_case.capture,12447 else_case.capture,
12447 else_case.has_tag_capture,12448 else_case.has_tag_capture,
12448 if (else_case.is_inline) cond_ref else .none,12449 prong_kind,
12449 .special,
12450 validated_switch.else_err_ty,12450 validated_switch.else_err_ty,
12451 merges,12451 merges,
12452 switch_inst,12452 switch_inst,
...@@ -12456,11 +12456,10 @@ fn resolveSwitchBlock(...@@ -12456,11 +12456,10 @@ fn resolveSwitchBlock(
1245612456
12457 // catch-all prong12457 // catch-all prong
1245812458
12459 const index, const body, const capture, const has_tag_capture, const is_inline = switch (catch_all_case) {12459 const index, const body, const capture, const has_tag_capture, const is_inline = if (under_prong) |under|
12460 .@"else" => .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline },12460 .{ under.index, under.body, under.capture, under.has_tag_capture, false }
12461 .under => .{ under_prong.?.index, under_prong.?.body, under_prong.?.capture, under_prong.?.has_tag_capture, false },12461 else
12462 .none => unreachable,12462 .{ else_case.index, else_case.body, else_case.capture, else_case.has_tag_capture, else_case.is_inline };
12463 };
12464 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref);12463 if (err_set) try sema.maybeErrorUnwrapComptime(child_block, body, cond_ref);
12465 if (union_originally) {12464 if (union_originally) {
12466 for (validated_switch.seen_enum_fields, 0..) |maybe_seen, field_i| {12465 for (validated_switch.seen_enum_fields, 0..) |maybe_seen, field_i| {
...@@ -12471,6 +12470,10 @@ fn resolveSwitchBlock(...@@ -12471,6 +12470,10 @@ fn resolveSwitchBlock(
12471 return .unreachable_value;12470 return .unreachable_value;
12472 }12471 }
12473 }12472 }
12473 const prong_kind: SwitchProngKind = if (is_inline)
12474 .{ .inline_ref = cond_ref }
12475 else
12476 .special;
12474 return sema.resolveSwitchProng(12477 return sema.resolveSwitchProng(
12475 block,12478 block,
12476 child_block,12479 child_block,
...@@ -12483,8 +12486,7 @@ fn resolveSwitchBlock(...@@ -12483,8 +12486,7 @@ fn resolveSwitchBlock(
12483 } }),12486 } }),
12484 capture,12487 capture,
12485 has_tag_capture,12488 has_tag_capture,
12486 if (is_inline) cond_ref else .none,12489 prong_kind,
12487 .special,
12488 validated_switch.else_err_ty,12490 validated_switch.else_err_ty,
12489 merges,12491 merges,
12490 switch_inst,12492 switch_inst,
...@@ -12520,9 +12522,9 @@ const SwitchOperand = union(enum) {...@@ -12520,9 +12522,9 @@ const SwitchOperand = union(enum) {
12520 },12522 },
12521};12523};
1252212524
12523const CatchAllSwitchCase = enum { none, @"else", under };
12524
12525const SwitchProngKind = union(enum) {12525const SwitchProngKind = union(enum) {
12526 /// Prefer populating this field over the others, if possible.
12527 inline_ref: Air.Inst.Ref,
12526 item_refs: []const Air.Inst.Ref,12528 item_refs: []const Air.Inst.Ref,
12527 has_ranges,12529 has_ranges,
12528 special,12530 special,
...@@ -12541,7 +12543,6 @@ fn resolveSwitchProng(...@@ -12541,7 +12543,6 @@ fn resolveSwitchProng(
12541 capture_src: LazySrcLoc,12543 capture_src: LazySrcLoc,
12542 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,12544 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
12543 has_tag_capture: bool,12545 has_tag_capture: bool,
12544 inline_case_capture: Air.Inst.Ref,
12545 kind: SwitchProngKind,12546 kind: SwitchProngKind,
12546 else_err_ty: ?Type,12547 else_err_ty: ?Type,
12547 merges: *Block.Merges,12548 merges: *Block.Merges,
...@@ -12569,7 +12570,6 @@ fn resolveSwitchProng(...@@ -12569,7 +12570,6 @@ fn resolveSwitchProng(
12569 capture_src,12570 capture_src,
12570 capture == .by_ref,12571 capture == .by_ref,
12571 kind,12572 kind,
12572 inline_case_capture,
12573 else_err_ty,12573 else_err_ty,
12574 );12574 );
12575 assert(!sema.typeOf(payload_ref).isNoReturn(sema.pt.zcu));12575 assert(!sema.typeOf(payload_ref).isNoReturn(sema.pt.zcu));
...@@ -12585,7 +12585,6 @@ fn resolveSwitchProng(...@@ -12585,7 +12585,6 @@ fn resolveSwitchProng(
12585 operand.simple.by_val,12585 operand.simple.by_val,
12586 sema.typeOf(operand.simple.by_val),12586 sema.typeOf(operand.simple.by_val),
12587 capture_src,12587 capture_src,
12588 inline_case_capture,
12589 kind,12588 kind,
12590 );12589 );
12591 sema.inst_map.putAssumeCapacity(tag_inst, tag_ref);12590 sema.inst_map.putAssumeCapacity(tag_inst, tag_ref);
...@@ -12637,7 +12636,6 @@ fn analyzeSwitchProng(...@@ -12637,7 +12636,6 @@ fn analyzeSwitchProng(
12637 capture_src: LazySrcLoc,12636 capture_src: LazySrcLoc,
12638 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,12637 capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
12639 has_tag_capture: bool,12638 has_tag_capture: bool,
12640 inline_case_capture: Air.Inst.Ref,
12641 kind: SwitchProngKind,12639 kind: SwitchProngKind,
12642 else_err_ty: ?Type,12640 else_err_ty: ?Type,
12643 switch_inst: Zir.Inst.Index,12641 switch_inst: Zir.Inst.Index,
...@@ -12664,7 +12662,7 @@ fn analyzeSwitchProng(...@@ -12664,7 +12662,7 @@ fn analyzeSwitchProng(
12664 // No need to load the operand for this prong!12662 // No need to load the operand for this prong!
12665 break :load_operand .{ undefined, undefined };12663 break :load_operand .{ undefined, undefined };
12666 }12664 }
12667 if (inline_case_capture != .none and12665 if (kind == .inline_ref and
12668 !(capture != .none and operand_ty.zigTypeTag(zcu) == .@"union"))12666 !(capture != .none and operand_ty.zigTypeTag(zcu) == .@"union"))
12669 {12667 {
12670 // We only need to load the operand if there's a union payload capture12668 // We only need to load the operand if there's a union payload capture
...@@ -12698,7 +12696,6 @@ fn analyzeSwitchProng(...@@ -12698,7 +12696,6 @@ fn analyzeSwitchProng(
12698 capture_src,12696 capture_src,
12699 capture == .by_ref,12697 capture == .by_ref,
12700 kind,12698 kind,
12701 inline_case_capture,
12702 else_err_ty,12699 else_err_ty,
12703 );12700 );
12704 assert(!sema.typeOf(payload_ref).isNoReturn(sema.pt.zcu));12701 assert(!sema.typeOf(payload_ref).isNoReturn(sema.pt.zcu));
...@@ -12714,7 +12711,6 @@ fn analyzeSwitchProng(...@@ -12714,7 +12711,6 @@ fn analyzeSwitchProng(
12714 operand_val,12711 operand_val,
12715 operand_ty,12712 operand_ty,
12716 capture_src,12713 capture_src,
12717 inline_case_capture,
12718 kind,12714 kind,
12719 );12715 );
12720 sema.inst_map.putAssumeCapacity(tag_inst, tag_ref);12716 sema.inst_map.putAssumeCapacity(tag_inst, tag_ref);
...@@ -12735,7 +12731,6 @@ fn analyzeSwitchTagCapture(...@@ -12735,7 +12731,6 @@ fn analyzeSwitchTagCapture(
12735 operand_val: Air.Inst.Ref,12731 operand_val: Air.Inst.Ref,
12736 operand_ty: Type,12732 operand_ty: Type,
12737 capture_src: LazySrcLoc,12733 capture_src: LazySrcLoc,
12738 inline_case_capture: Air.Inst.Ref,
12739 kind: SwitchProngKind,12734 kind: SwitchProngKind,
12740) CompileError!Air.Inst.Ref {12735) CompileError!Air.Inst.Ref {
12741 const pt = sema.pt;12736 const pt = sema.pt;
...@@ -12751,12 +12746,11 @@ fn analyzeSwitchTagCapture(...@@ -12751,12 +12746,11 @@ fn analyzeSwitchTagCapture(
12751 operand_ty.fmt(pt),12746 operand_ty.fmt(pt),
12752 });12747 });
12753 }12748 }
12754 if (inline_case_capture != .none) {
12755 return inline_case_capture; // this already is the tag, it's what we're switching on!
12756 }
12757 switch (kind) {12749 switch (kind) {
12758 .has_ranges, .special => {},12750 .has_ranges => unreachable,
12751 .inline_ref => |ref| return ref,
12759 .item_refs => |refs| if (refs.len == 1) return refs[0],12752 .item_refs => |refs| if (refs.len == 1) return refs[0],
12753 .special => {},
12760 }12754 }
12761 const tag_ty = operand_ty.unionTagType(zcu).?;12755 const tag_ty = operand_ty.unionTagType(zcu).?;
12762 return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src);12756 return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src);
...@@ -12775,8 +12769,6 @@ fn analyzeSwitchPayloadCapture(...@@ -12775,8 +12769,6 @@ fn analyzeSwitchPayloadCapture(
12775 capture_src: LazySrcLoc,12769 capture_src: LazySrcLoc,
12776 capture_by_ref: bool,12770 capture_by_ref: bool,
12777 kind: SwitchProngKind,12771 kind: SwitchProngKind,
12778 /// If this is not `.none`, this is an inline capture.
12779 inline_case_capture: Air.Inst.Ref,
12780 else_err_ty: ?Type,12772 else_err_ty: ?Type,
12781) CompileError!Air.Inst.Ref {12773) CompileError!Air.Inst.Ref {
12782 const pt = sema.pt;12774 const pt = sema.pt;
...@@ -12785,8 +12777,8 @@ fn analyzeSwitchPayloadCapture(...@@ -12785,8 +12777,8 @@ fn analyzeSwitchPayloadCapture(
1278512777
12786 const switch_node_offset = operand_src.offset.node_offset_switch_operand;12778 const switch_node_offset = operand_src.offset.node_offset_switch_operand;
1278712779
12788 if (inline_case_capture != .none) {12780 if (kind == .inline_ref) {
12789 const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, inline_case_capture, undefined) catch unreachable;12781 const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, kind.inline_ref, undefined) catch unreachable;
12790 if (operand_ty.zigTypeTag(zcu) == .@"union") {12782 if (operand_ty.zigTypeTag(zcu) == .@"union") {
12791 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);12783 const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);
12792 const union_obj = zcu.typeToUnion(operand_ty).?;12784 const union_obj = zcu.typeToUnion(operand_ty).?;
...@@ -12812,7 +12804,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12812,7 +12804,7 @@ fn analyzeSwitchPayloadCapture(
12812 } else if (capture_by_ref) {12804 } else if (capture_by_ref) {
12813 return sema.uavRef(item_val.toIntern());12805 return sema.uavRef(item_val.toIntern());
12814 } else {12806 } else {
12815 return inline_case_capture;12807 return kind.inline_ref;
12816 }12808 }
12817 }12809 }
1281812810
...@@ -13155,7 +13147,7 @@ fn analyzeSwitchPayloadCapture(...@@ -13155,7 +13147,7 @@ fn analyzeSwitchPayloadCapture(
13155 return operand_ptr;13147 return operand_ptr;
13156 }13148 }
13157 switch (kind) {13149 switch (kind) {
13158 .special => unreachable,13150 .inline_ref, .special => unreachable,
13159 .item_refs => |case_vals| {13151 .item_refs => |case_vals| {
13160 // If there's only a single item, the capture is comptime-known!13152 // If there's only a single item, the capture is comptime-known!
13161 if (case_vals.len == 1) return case_vals[0];13153 if (case_vals.len == 1) return case_vals[0];
test/behavior/switch.zig+7-1
...@@ -1308,7 +1308,7 @@ test "single-item prong in switch on enum has comptime-known capture" {...@@ -1308,7 +1308,7 @@ test "single-item prong in switch on enum has comptime-known capture" {
1308 try comptime E.doTheTest(.a);1308 try comptime E.doTheTest(.a);
1309}1309}
13101310
1311test "single-range switch prong capture" {1311test "single range switch prong capture" {
1312 const S = struct {1312 const S = struct {
1313 fn doTheTest(x: u8) !void {1313 fn doTheTest(x: u8) !void {
1314 switch (x) {1314 switch (x) {
...@@ -1317,6 +1317,12 @@ test "single-range switch prong capture" {...@@ -1317,6 +1317,12 @@ test "single-range switch prong capture" {
1317 },1317 },
1318 else => return error.TestFailed,1318 else => return error.TestFailed,
1319 }1319 }
1320 switch (x) {
1321 1...5, 6 => |val| {
1322 try expect(val == 2);
1323 },
1324 else => return error.TestFailed,
1325 }
1320 }1326 }
1321 };1327 };
1322 try S.doTheTest(2);1328 try S.doTheTest(2);