| ... | @@ -2729,6 +2729,8 @@ fn analyzeSwitch( | ... | @@ -2729,6 +2729,8 @@ fn analyzeSwitch( |
| 2729 | src_node_offset: i32, | 2729 | src_node_offset: i32, |
| 2730 | ) InnerError!*Inst { | 2730 | ) InnerError!*Inst { |
| 2731 | const gpa = sema.gpa; | 2731 | const gpa = sema.gpa; |
| | 2732 | const mod = sema.mod; |
| | 2733 | |
| 2732 | const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) { | 2734 | const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) { |
| 2733 | .none => .{ .body = &.{}, .end = extra_end }, | 2735 | .none => .{ .body = &.{}, .end = extra_end }, |
| 2734 | .under, .@"else" => blk: { | 2736 | .under, .@"else" => blk: { |
| ... | @@ -2748,14 +2750,14 @@ fn analyzeSwitch( | ... | @@ -2748,14 +2750,14 @@ fn analyzeSwitch( |
| 2748 | // Validate usage of '_' prongs. | 2750 | // Validate usage of '_' prongs. |
| 2749 | if (special_prong == .under and !operand.ty.isExhaustiveEnum()) { | 2751 | if (special_prong == .under and !operand.ty.isExhaustiveEnum()) { |
| 2750 | const msg = msg: { | 2752 | const msg = msg: { |
| 2751 | const msg = try sema.mod.errMsg( | 2753 | const msg = try mod.errMsg( |
| 2752 | &block.base, | 2754 | &block.base, |
| 2753 | src, | 2755 | src, |
| 2754 | "'_' prong only allowed when switching on non-exhaustive enums", | 2756 | "'_' prong only allowed when switching on non-exhaustive enums", |
| 2755 | .{}, | 2757 | .{}, |
| 2756 | ); | 2758 | ); |
| 2757 | errdefer msg.destroy(gpa); | 2759 | errdefer msg.destroy(gpa); |
| 2758 | try sema.mod.errNote( | 2760 | try mod.errNote( |
| 2759 | &block.base, | 2761 | &block.base, |
| 2760 | special_prong_src, | 2762 | special_prong_src, |
| 2761 | msg, | 2763 | msg, |
| ... | @@ -2764,14 +2766,121 @@ fn analyzeSwitch( | ... | @@ -2764,14 +2766,121 @@ fn analyzeSwitch( |
| 2764 | ); | 2766 | ); |
| 2765 | break :msg msg; | 2767 | break :msg msg; |
| 2766 | }; | 2768 | }; |
| 2767 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | 2769 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 2768 | } | 2770 | } |
| 2769 | | 2771 | |
| 2770 | // Validate for duplicate items, missing else prong, and invalid range. | 2772 | // Validate for duplicate items, missing else prong, and invalid range. |
| 2771 | switch (operand.ty.zigTypeTag()) { | 2773 | switch (operand.ty.zigTypeTag()) { |
| 2772 | .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}), | 2774 | .Enum => { |
| 2773 | .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}), | 2775 | var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount()); |
| 2774 | .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}), | 2776 | defer gpa.free(seen_fields); |
| | 2777 | |
| | 2778 | var extra_index: usize = special.end; |
| | 2779 | { |
| | 2780 | var scalar_i: u32 = 0; |
| | 2781 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| | 2782 | const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]); |
| | 2783 | extra_index += 1; |
| | 2784 | const body_len = sema.code.extra[extra_index]; |
| | 2785 | extra_index += 1; |
| | 2786 | const body = sema.code.extra[extra_index..][0..body_len]; |
| | 2787 | extra_index += body_len; |
| | 2788 | |
| | 2789 | try sema.validateSwitchItemEnum( |
| | 2790 | block, |
| | 2791 | seen_fields, |
| | 2792 | item_ref, |
| | 2793 | src_node_offset, |
| | 2794 | .{ .scalar = scalar_i }, |
| | 2795 | ); |
| | 2796 | } |
| | 2797 | } |
| | 2798 | { |
| | 2799 | var multi_i: u32 = 0; |
| | 2800 | while (multi_i < multi_cases_len) : (multi_i += 1) { |
| | 2801 | const items_len = sema.code.extra[extra_index]; |
| | 2802 | extra_index += 1; |
| | 2803 | const ranges_len = sema.code.extra[extra_index]; |
| | 2804 | extra_index += 1; |
| | 2805 | const body_len = sema.code.extra[extra_index]; |
| | 2806 | extra_index += 1; |
| | 2807 | const items = sema.code.refSlice(extra_index, items_len); |
| | 2808 | extra_index += items_len + body_len; |
| | 2809 | |
| | 2810 | for (items) |item_ref, item_i| { |
| | 2811 | try sema.validateSwitchItemEnum( |
| | 2812 | block, |
| | 2813 | seen_fields, |
| | 2814 | item_ref, |
| | 2815 | src_node_offset, |
| | 2816 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| | 2817 | ); |
| | 2818 | } |
| | 2819 | |
| | 2820 | try sema.validateSwitchNoRange(block, ranges_len, operand.ty, src_node_offset); |
| | 2821 | } |
| | 2822 | } |
| | 2823 | const all_tags_handled = for (seen_fields) |seen_src| { |
| | 2824 | if (seen_src == null) break false; |
| | 2825 | } else true; |
| | 2826 | |
| | 2827 | switch (special_prong) { |
| | 2828 | .none => { |
| | 2829 | if (!all_tags_handled) { |
| | 2830 | const msg = msg: { |
| | 2831 | const msg = try mod.errMsg( |
| | 2832 | &block.base, |
| | 2833 | src, |
| | 2834 | "switch must handle all possibilities", |
| | 2835 | .{}, |
| | 2836 | ); |
| | 2837 | errdefer msg.destroy(sema.gpa); |
| | 2838 | try mod.errNoteNonLazy( |
| | 2839 | operand.ty.declSrcLoc(), |
| | 2840 | msg, |
| | 2841 | "enum '{}' declared here", |
| | 2842 | .{operand.ty}, |
| | 2843 | ); |
| | 2844 | for (seen_fields) |seen_src, i| { |
| | 2845 | if (seen_src != null) continue; |
| | 2846 | |
| | 2847 | const field_name = operand.ty.enumFieldName(i); |
| | 2848 | |
| | 2849 | // TODO have this point to the tag decl instead of here |
| | 2850 | try mod.errNote( |
| | 2851 | &block.base, |
| | 2852 | src, |
| | 2853 | msg, |
| | 2854 | "unhandled enumeration value: '{s}", |
| | 2855 | .{field_name}, |
| | 2856 | ); |
| | 2857 | } |
| | 2858 | break :msg msg; |
| | 2859 | }; |
| | 2860 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| | 2861 | } |
| | 2862 | }, |
| | 2863 | .under => { |
| | 2864 | if (all_tags_handled) return mod.fail( |
| | 2865 | &block.base, |
| | 2866 | special_prong_src, |
| | 2867 | "unreachable '_' prong; all cases already handled", |
| | 2868 | .{}, |
| | 2869 | ); |
| | 2870 | }, |
| | 2871 | .@"else" => { |
| | 2872 | if (all_tags_handled) return mod.fail( |
| | 2873 | &block.base, |
| | 2874 | special_prong_src, |
| | 2875 | "unreachable else prong; all cases already handled", |
| | 2876 | .{}, |
| | 2877 | ); |
| | 2878 | }, |
| | 2879 | } |
| | 2880 | }, |
| | 2881 | |
| | 2882 | .ErrorSet => return mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}), |
| | 2883 | .Union => return mod.fail(&block.base, src, "TODO validate switch .Union", .{}), |
| 2775 | .Int, .ComptimeInt => { | 2884 | .Int, .ComptimeInt => { |
| 2776 | var range_set = RangeSet.init(gpa); | 2885 | var range_set = RangeSet.init(gpa); |
| 2777 | defer range_set.deinit(); | 2886 | defer range_set.deinit(); |
| ... | @@ -2844,11 +2953,11 @@ fn analyzeSwitch( | ... | @@ -2844,11 +2953,11 @@ fn analyzeSwitch( |
| 2844 | var arena = std.heap.ArenaAllocator.init(gpa); | 2953 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 2845 | defer arena.deinit(); | 2954 | defer arena.deinit(); |
| 2846 | | 2955 | |
| 2847 | const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget()); | 2956 | const min_int = try operand.ty.minInt(&arena, mod.getTarget()); |
| 2848 | const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget()); | 2957 | const max_int = try operand.ty.maxInt(&arena, mod.getTarget()); |
| 2849 | if (try range_set.spans(min_int, max_int)) { | 2958 | if (try range_set.spans(min_int, max_int)) { |
| 2850 | if (special_prong == .@"else") { | 2959 | if (special_prong == .@"else") { |
| 2851 | return sema.mod.fail( | 2960 | return mod.fail( |
| 2852 | &block.base, | 2961 | &block.base, |
| 2853 | special_prong_src, | 2962 | special_prong_src, |
| 2854 | "unreachable else prong; all cases already handled", | 2963 | "unreachable else prong; all cases already handled", |
| ... | @@ -2859,7 +2968,7 @@ fn analyzeSwitch( | ... | @@ -2859,7 +2968,7 @@ fn analyzeSwitch( |
| 2859 | } | 2968 | } |
| 2860 | } | 2969 | } |
| 2861 | if (special_prong != .@"else") { | 2970 | if (special_prong != .@"else") { |
| 2862 | return sema.mod.fail( | 2971 | return mod.fail( |
| 2863 | &block.base, | 2972 | &block.base, |
| 2864 | src, | 2973 | src, |
| 2865 | "switch must handle all possibilities", | 2974 | "switch must handle all possibilities", |
| ... | @@ -2922,7 +3031,7 @@ fn analyzeSwitch( | ... | @@ -2922,7 +3031,7 @@ fn analyzeSwitch( |
| 2922 | switch (special_prong) { | 3031 | switch (special_prong) { |
| 2923 | .@"else" => { | 3032 | .@"else" => { |
| 2924 | if (true_count + false_count == 2) { | 3033 | if (true_count + false_count == 2) { |
| 2925 | return sema.mod.fail( | 3034 | return mod.fail( |
| 2926 | &block.base, | 3035 | &block.base, |
| 2927 | src, | 3036 | src, |
| 2928 | "unreachable else prong; all cases already handled", | 3037 | "unreachable else prong; all cases already handled", |
| ... | @@ -2932,7 +3041,7 @@ fn analyzeSwitch( | ... | @@ -2932,7 +3041,7 @@ fn analyzeSwitch( |
| 2932 | }, | 3041 | }, |
| 2933 | .under, .none => { | 3042 | .under, .none => { |
| 2934 | if (true_count + false_count < 2) { | 3043 | if (true_count + false_count < 2) { |
| 2935 | return sema.mod.fail( | 3044 | return mod.fail( |
| 2936 | &block.base, | 3045 | &block.base, |
| 2937 | src, | 3046 | src, |
| 2938 | "switch must handle all possibilities", | 3047 | "switch must handle all possibilities", |
| ... | @@ -2944,7 +3053,7 @@ fn analyzeSwitch( | ... | @@ -2944,7 +3053,7 @@ fn analyzeSwitch( |
| 2944 | }, | 3053 | }, |
| 2945 | .EnumLiteral, .Void, .Fn, .Pointer, .Type => { | 3054 | .EnumLiteral, .Void, .Fn, .Pointer, .Type => { |
| 2946 | if (special_prong != .@"else") { | 3055 | if (special_prong != .@"else") { |
| 2947 | return sema.mod.fail( | 3056 | return mod.fail( |
| 2948 | &block.base, | 3057 | &block.base, |
| 2949 | src, | 3058 | src, |
| 2950 | "else prong required when switching on type '{}'", | 3059 | "else prong required when switching on type '{}'", |
| ... | @@ -3016,7 +3125,7 @@ fn analyzeSwitch( | ... | @@ -3016,7 +3125,7 @@ fn analyzeSwitch( |
| 3016 | .AnyFrame, | 3125 | .AnyFrame, |
| 3017 | .ComptimeFloat, | 3126 | .ComptimeFloat, |
| 3018 | .Float, | 3127 | .Float, |
| 3019 | => return sema.mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{ | 3128 | => return mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{ |
| 3020 | operand.ty, | 3129 | operand.ty, |
| 3021 | }), | 3130 | }), |
| 3022 | } | 3131 | } |
| ... | @@ -3291,7 +3400,7 @@ fn resolveSwitchItemVal( | ... | @@ -3291,7 +3400,7 @@ fn resolveSwitchItemVal( |
| 3291 | switch_node_offset: i32, | 3400 | switch_node_offset: i32, |
| 3292 | switch_prong_src: AstGen.SwitchProngSrc, | 3401 | switch_prong_src: AstGen.SwitchProngSrc, |
| 3293 | range_expand: AstGen.SwitchProngSrc.RangeExpand, | 3402 | range_expand: AstGen.SwitchProngSrc.RangeExpand, |
| 3294 | ) InnerError!Value { | 3403 | ) InnerError!TypedValue { |
| 3295 | const item = try sema.resolveInst(item_ref); | 3404 | const item = try sema.resolveInst(item_ref); |
| 3296 | // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc | 3405 | // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc |
| 3297 | // because we only have the switch AST node. Only if we know for sure we need to report | 3406 | // because we only have the switch AST node. Only if we know for sure we need to report |
| ... | @@ -3301,7 +3410,7 @@ fn resolveSwitchItemVal( | ... | @@ -3301,7 +3410,7 @@ fn resolveSwitchItemVal( |
| 3301 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); | 3410 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); |
| 3302 | return sema.failWithUseOfUndef(block, src); | 3411 | return sema.failWithUseOfUndef(block, src); |
| 3303 | } | 3412 | } |
| 3304 | return val; | 3413 | return TypedValue{ .ty = item.ty, .val = val }; |
| 3305 | } | 3414 | } |
| 3306 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); | 3415 | const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand); |
| 3307 | return sema.failWithNeededComptime(block, src); | 3416 | return sema.failWithNeededComptime(block, src); |
| ... | @@ -3316,8 +3425,8 @@ fn validateSwitchRange( | ... | @@ -3316,8 +3425,8 @@ fn validateSwitchRange( |
| 3316 | src_node_offset: i32, | 3425 | src_node_offset: i32, |
| 3317 | switch_prong_src: AstGen.SwitchProngSrc, | 3426 | switch_prong_src: AstGen.SwitchProngSrc, |
| 3318 | ) InnerError!void { | 3427 | ) InnerError!void { |
| 3319 | const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); | 3428 | const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; |
| 3320 | const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); | 3429 | const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; |
| 3321 | const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src); | 3430 | const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src); |
| 3322 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 3431 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 3323 | } | 3432 | } |
| ... | @@ -3330,11 +3439,46 @@ fn validateSwitchItem( | ... | @@ -3330,11 +3439,46 @@ fn validateSwitchItem( |
| 3330 | src_node_offset: i32, | 3439 | src_node_offset: i32, |
| 3331 | switch_prong_src: AstGen.SwitchProngSrc, | 3440 | switch_prong_src: AstGen.SwitchProngSrc, |
| 3332 | ) InnerError!void { | 3441 | ) InnerError!void { |
| 3333 | const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 3442 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3334 | const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src); | 3443 | const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src); |
| 3335 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 3444 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 3336 | } | 3445 | } |
| 3337 | | 3446 | |
| | 3447 | fn validateSwitchItemEnum( |
| | 3448 | sema: *Sema, |
| | 3449 | block: *Scope.Block, |
| | 3450 | seen_fields: []?AstGen.SwitchProngSrc, |
| | 3451 | item_ref: zir.Inst.Ref, |
| | 3452 | src_node_offset: i32, |
| | 3453 | switch_prong_src: AstGen.SwitchProngSrc, |
| | 3454 | ) InnerError!void { |
| | 3455 | const mod = sema.mod; |
| | 3456 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| | 3457 | const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse { |
| | 3458 | const msg = msg: { |
| | 3459 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| | 3460 | const msg = try mod.errMsg( |
| | 3461 | &block.base, |
| | 3462 | src, |
| | 3463 | "enum '{}' has no tag with value '{}'", |
| | 3464 | .{ item_tv.ty, item_tv.val }, |
| | 3465 | ); |
| | 3466 | errdefer msg.destroy(sema.gpa); |
| | 3467 | try mod.errNoteNonLazy( |
| | 3468 | item_tv.ty.declSrcLoc(), |
| | 3469 | msg, |
| | 3470 | "enum declared here", |
| | 3471 | .{}, |
| | 3472 | ); |
| | 3473 | break :msg msg; |
| | 3474 | }; |
| | 3475 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| | 3476 | }; |
| | 3477 | const maybe_prev_src = seen_fields[field_index]; |
| | 3478 | seen_fields[field_index] = switch_prong_src; |
| | 3479 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| | 3480 | } |
| | 3481 | |
| 3338 | fn validateSwitchDupe( | 3482 | fn validateSwitchDupe( |
| 3339 | sema: *Sema, | 3483 | sema: *Sema, |
| 3340 | block: *Scope.Block, | 3484 | block: *Scope.Block, |
| ... | @@ -3343,17 +3487,18 @@ fn validateSwitchDupe( | ... | @@ -3343,17 +3487,18 @@ fn validateSwitchDupe( |
| 3343 | src_node_offset: i32, | 3487 | src_node_offset: i32, |
| 3344 | ) InnerError!void { | 3488 | ) InnerError!void { |
| 3345 | const prev_prong_src = maybe_prev_src orelse return; | 3489 | const prev_prong_src = maybe_prev_src orelse return; |
| | 3490 | const mod = sema.mod; |
| 3346 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); | 3491 | const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| 3347 | const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none); | 3492 | const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none); |
| 3348 | const msg = msg: { | 3493 | const msg = msg: { |
| 3349 | const msg = try sema.mod.errMsg( | 3494 | const msg = try mod.errMsg( |
| 3350 | &block.base, | 3495 | &block.base, |
| 3351 | src, | 3496 | src, |
| 3352 | "duplicate switch value", | 3497 | "duplicate switch value", |
| 3353 | .{}, | 3498 | .{}, |
| 3354 | ); | 3499 | ); |
| 3355 | errdefer msg.destroy(sema.gpa); | 3500 | errdefer msg.destroy(sema.gpa); |
| 3356 | try sema.mod.errNote( | 3501 | try mod.errNote( |
| 3357 | &block.base, | 3502 | &block.base, |
| 3358 | prev_src, | 3503 | prev_src, |
| 3359 | msg, | 3504 | msg, |
| ... | @@ -3362,7 +3507,7 @@ fn validateSwitchDupe( | ... | @@ -3362,7 +3507,7 @@ fn validateSwitchDupe( |
| 3362 | ); | 3507 | ); |
| 3363 | break :msg msg; | 3508 | break :msg msg; |
| 3364 | }; | 3509 | }; |
| 3365 | return sema.mod.failWithOwnedErrorMsg(&block.base, msg); | 3510 | return mod.failWithOwnedErrorMsg(&block.base, msg); |
| 3366 | } | 3511 | } |
| 3367 | | 3512 | |
| 3368 | fn validateSwitchItemBool( | 3513 | fn validateSwitchItemBool( |
| ... | @@ -3374,7 +3519,7 @@ fn validateSwitchItemBool( | ... | @@ -3374,7 +3519,7 @@ fn validateSwitchItemBool( |
| 3374 | src_node_offset: i32, | 3519 | src_node_offset: i32, |
| 3375 | switch_prong_src: AstGen.SwitchProngSrc, | 3520 | switch_prong_src: AstGen.SwitchProngSrc, |
| 3376 | ) InnerError!void { | 3521 | ) InnerError!void { |
| 3377 | const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 3522 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3378 | if (item_val.toBool()) { | 3523 | if (item_val.toBool()) { |
| 3379 | true_count.* += 1; | 3524 | true_count.* += 1; |
| 3380 | } else { | 3525 | } else { |
| ... | @@ -3396,7 +3541,7 @@ fn validateSwitchItemSparse( | ... | @@ -3396,7 +3541,7 @@ fn validateSwitchItemSparse( |
| 3396 | src_node_offset: i32, | 3541 | src_node_offset: i32, |
| 3397 | switch_prong_src: AstGen.SwitchProngSrc, | 3542 | switch_prong_src: AstGen.SwitchProngSrc, |
| 3398 | ) InnerError!void { | 3543 | ) InnerError!void { |
| 3399 | const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 3544 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; |
| 3400 | const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; | 3545 | const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; |
| 3401 | return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset); | 3546 | return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset); |
| 3402 | } | 3547 | } |