authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2025-12-17 20:01:36+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-11 11:37:16+00:00
logd840bb511839464c852699acce471efccdd67f3e
treec7eebab23484f8835231e35845273a834202e17c
parente0108dec54deaf044e869bb76aa4a40813913277
signaturelock-open Commit is signed but in an unrecognized format.

AstGen: improve ergonomics of `Scope`

Adds `Scope.Unwrapped`, a simple union of pointers to already-casted scopes with `Scope.Tag` as its tag enum. This pairs very nicely with labeled switch and gets rid of almost every `scope.cast(...).?`, improving developer QOL :)

1 files changed, 122 insertions(+), 155 deletions(-)

lib/std/zig/AstGen.zig+122-155
......@@ -2161,10 +2161,9 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
21612161 const opt_break_label, const opt_rhs = tree.nodeData(node).opt_token_and_opt_node;
21622162
21632163 // Look for the label in the scope.
2164 var scope = parent_scope;
2165 find_scope: switch (scope.tag) {
2166 .gen_zir => {
2167 const gen_zir = scope.cast(GenZir).?;
2164 find_scope: switch (parent_scope.unwrap()) {
2165 .gen_zir => |gen_zir| {
2166 const scope = &gen_zir.base;
21682167
21692168 if (gen_zir.cur_defer_node.unwrap()) |cur_defer_node| {
21702169 // We are breaking out of a `defer` block.
......@@ -2185,13 +2184,11 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
21852184 }
21862185 }
21872186 // gz without or with different label, continue to parent scopes.
2188 scope = gen_zir.parent;
2189 continue :find_scope scope.tag;
2187 continue :find_scope gen_zir.parent.unwrap();
21902188 } else if (!gen_zir.allow_unlabeled_control_flow) {
21912189 // This `break` is unlabeled and the gz we've found doesn't allow
21922190 // unlabeled control flow. Continue to parent scopes.
2193 scope = gen_zir.parent;
2194 continue :find_scope scope.tag;
2191 continue :find_scope gen_zir.parent.unwrap();
21952192 }
21962193
21972194 const break_tag: Zir.Inst.Tag = if (gen_zir.is_inline)
......@@ -2236,18 +2233,9 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
22362233 return .unreachable_value;
22372234 }
22382235 },
2239 .local_val => {
2240 scope = scope.cast(Scope.LocalVal).?.parent;
2241 continue :find_scope scope.tag;
2242 },
2243 .local_ptr => {
2244 scope = scope.cast(Scope.LocalPtr).?.parent;
2245 continue :find_scope scope.tag;
2246 },
2247 .defer_normal, .defer_error => {
2248 scope = scope.cast(Scope.Defer).?.parent;
2249 continue :find_scope scope.tag;
2250 },
2236 .local_val => |local_val| continue :find_scope local_val.parent.unwrap(),
2237 .local_ptr => |local_ptr| continue :find_scope local_ptr.parent.unwrap(),
2238 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
22512239 .namespace => {
22522240 if (opt_break_label.unwrap()) |break_label| {
22532241 const label_name = try astgen.identifierTokenString(break_label);
......@@ -2270,10 +2258,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
22702258 }
22712259
22722260 // Look for the label in the scope.
2273 var scope = parent_scope;
2274 find_scope: switch (scope.tag) {
2275 .gen_zir => {
2276 const gen_zir = scope.cast(GenZir).?;
2261 find_scope: switch (parent_scope.unwrap()) {
2262 .gen_zir => |gen_zir| {
2263 const scope = &gen_zir.base;
22772264
22782265 if (gen_zir.cur_defer_node.unwrap()) |cur_defer_node| {
22792266 return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{
......@@ -2305,24 +2292,21 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
23052292 }
23062293 }
23072294 // gz without or with different label, continue to parent scopes.
2308 scope = gen_zir.parent;
2309 continue :find_scope scope.tag;
2295 continue :find_scope gen_zir.parent.unwrap();
23102296 } else if (gen_zir.allow_unlabeled_control_flow) {
23112297 // This `continue` is unlabeled. If the gz we've found doesn't
23122298 // provide a `continue` target or corresponds to a labeled
23132299 // `switch`, ignore it and continue to parent scopes.
23142300 switch (gen_zir.continue_target) {
23152301 .none, .switch_continue => {
2316 scope = gen_zir.parent;
2317 continue :find_scope scope.tag;
2302 continue :find_scope gen_zir.parent.unwrap();
23182303 },
23192304 .@"break" => {},
23202305 }
23212306 } else {
23222307 // We don't have a break label and the gz we found doesn't allow
23232308 // unlabeled control flow, so we continue to its parent scopes.
2324 scope = gen_zir.parent;
2325 continue :find_scope scope.tag;
2309 continue :find_scope gen_zir.parent.unwrap();
23262310 }
23272311
23282312 switch (gen_zir.continue_target) {
......@@ -2360,18 +2344,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
23602344 },
23612345 }
23622346 },
2363 .local_val => {
2364 scope = scope.cast(Scope.LocalVal).?.parent;
2365 continue :find_scope scope.tag;
2366 },
2367 .local_ptr => {
2368 scope = scope.cast(Scope.LocalPtr).?.parent;
2369 continue :find_scope scope.tag;
2370 },
2371 .defer_normal, .defer_error => {
2372 scope = scope.cast(Scope.Defer).?.parent;
2373 continue :find_scope scope.tag;
2374 },
2347 .local_val => |local_val| continue :find_scope local_val.parent.unwrap(),
2348 .local_ptr => |local_ptr| continue :find_scope local_ptr.parent.unwrap(),
2349 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
23752350 .namespace => {
23762351 if (opt_break_label.unwrap()) |break_label| {
23772352 const label_name = try astgen.identifierTokenString(break_label);
......@@ -2466,33 +2441,29 @@ fn blockExpr(
24662441
24672442fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.TokenIndex) !void {
24682443 // Look for the label in the scope.
2469 var scope = parent_scope;
2470 while (true) {
2471 switch (scope.tag) {
2472 .gen_zir => {
2473 const gen_zir = scope.cast(GenZir).?;
2474 if (gen_zir.label) |prev_label| {
2475 if (try astgen.tokenIdentEql(label, prev_label.token)) {
2476 const label_name = try astgen.identifierTokenString(label);
2477 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{
2478 label_name,
2479 }, &[_]u32{
2480 try astgen.errNoteTok(
2481 prev_label.token,
2482 "previous definition here",
2483 .{},
2484 ),
2485 });
2486 }
2444 find_scope: switch (parent_scope.unwrap()) {
2445 .gen_zir => |gen_zir| {
2446 if (gen_zir.label) |prev_label| {
2447 if (try astgen.tokenIdentEql(label, prev_label.token)) {
2448 const label_name = try astgen.identifierTokenString(label);
2449 return astgen.failTokNotes(label, "redefinition of label '{s}'", .{
2450 label_name,
2451 }, &[_]u32{
2452 try astgen.errNoteTok(
2453 prev_label.token,
2454 "previous definition here",
2455 .{},
2456 ),
2457 });
24872458 }
2488 scope = gen_zir.parent;
2489 },
2490 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2491 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2492 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2493 .namespace => break,
2494 .top => unreachable,
2495 }
2459 }
2460 continue :find_scope gen_zir.parent.unwrap();
2461 },
2462 .local_val => |local_val| continue :find_scope local_val.parent.unwrap(),
2463 .local_ptr => |local_ptr| continue :find_scope local_ptr.parent.unwrap(),
2464 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
2465 .namespace => break :find_scope,
2466 .top => unreachable,
24962467 }
24972468}
24982469
......@@ -3007,18 +2978,16 @@ fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
30072978 var need_err_code = false;
30082979 var scope = inner_scope;
30092980 while (scope != outer_scope) {
3010 switch (scope.tag) {
3011 .gen_zir => scope = scope.cast(GenZir).?.parent,
3012 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
3013 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
3014 .defer_normal => {
3015 const defer_scope = scope.cast(Scope.Defer).?;
2981 switch (scope.unwrap()) {
2982 .gen_zir => |gen_zir| scope = gen_zir.parent,
2983 .local_val => |local_val| scope = local_val.parent,
2984 .local_ptr => |local_ptr| scope = local_ptr.parent,
2985 .defer_normal => |defer_scope| {
30162986 scope = defer_scope.parent;
30172987
30182988 have_normal = true;
30192989 },
3020 .defer_error => {
3021 const defer_scope = scope.cast(Scope.Defer).?;
2990 .defer_error => |defer_scope| {
30222991 scope = defer_scope.parent;
30232992
30242993 have_err = true;
......@@ -3054,17 +3023,15 @@ fn genDefers(
30543023
30553024 var scope = inner_scope;
30563025 while (scope != outer_scope) {
3057 switch (scope.tag) {
3058 .gen_zir => scope = scope.cast(GenZir).?.parent,
3059 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
3060 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
3061 .defer_normal => {
3062 const defer_scope = scope.cast(Scope.Defer).?;
3026 switch (scope.unwrap()) {
3027 .gen_zir => |gen_zir| scope = gen_zir.parent,
3028 .local_val => |local_val| scope = local_val.parent,
3029 .local_ptr => |local_ptr| scope = local_ptr.parent,
3030 .defer_normal => |defer_scope| {
30633031 scope = defer_scope.parent;
30643032 try gz.addDefer(defer_scope.index, defer_scope.len);
30653033 },
3066 .defer_error => {
3067 const defer_scope = scope.cast(Scope.Defer).?;
3034 .defer_error => |defer_scope| {
30683035 scope = defer_scope.parent;
30693036 switch (which_ones) {
30703037 .both_sans_err => {
......@@ -3107,10 +3074,9 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
31073074
31083075 var scope = inner_scope;
31093076 while (scope != outer_scope) {
3110 switch (scope.tag) {
3111 .gen_zir => scope = scope.cast(GenZir).?.parent,
3112 .local_val => {
3113 const s = scope.cast(Scope.LocalVal).?;
3077 switch (scope.unwrap()) {
3078 .gen_zir => |gen_zir| scope = gen_zir.parent,
3079 .local_val => |s| {
31143080 if (s.used == .none and s.discarded == .none) {
31153081 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
31163082 } else if (s.used != .none and s.discarded != .none) {
......@@ -3120,8 +3086,7 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
31203086 }
31213087 scope = s.parent;
31223088 },
3123 .local_ptr => {
3124 const s = scope.cast(Scope.LocalPtr).?;
3089 .local_ptr => |s| {
31253090 if (s.used == .none and s.discarded == .none) {
31263091 try astgen.appendErrorTok(s.token_src, "unused {s}", .{@tagName(s.id_cat)});
31273092 } else {
......@@ -3136,10 +3101,9 @@ fn checkUsed(gz: *GenZir, outer_scope: *Scope, inner_scope: *Scope) InnerError!v
31363101 });
31373102 }
31383103 }
3139
31403104 scope = s.parent;
31413105 },
3142 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
3106 .defer_normal, .defer_error => |defer_scope| scope = defer_scope.parent,
31433107 .namespace => unreachable,
31443108 .top => unreachable,
31453109 }
......@@ -4805,13 +4769,11 @@ fn testDecl(
48054769
48064770 // Local variables, including function parameters.
48074771 const name_str_index = try astgen.identAsString(test_name_token);
4808 var s = scope;
48094772 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
48104773 var num_namespaces_out: u32 = 0;
48114774 var capturing_namespace: ?*Scope.Namespace = null;
4812 while (true) switch (s.tag) {
4813 .local_val => {
4814 const local_val = s.cast(Scope.LocalVal).?;
4775 find_scope: switch (scope.unwrap()) {
4776 .local_val => |local_val| {
48154777 if (local_val.name == name_str_index) {
48164778 local_val.used = .fromToken(test_name_token);
48174779 return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{
......@@ -4822,10 +4784,9 @@ fn testDecl(
48224784 }),
48234785 });
48244786 }
4825 s = local_val.parent;
4787 continue :find_scope local_val.parent.unwrap();
48264788 },
4827 .local_ptr => {
4828 const local_ptr = s.cast(Scope.LocalPtr).?;
4789 .local_ptr => |local_ptr| {
48294790 if (local_ptr.name == name_str_index) {
48304791 local_ptr.used = .fromToken(test_name_token);
48314792 return astgen.failTokNotes(test_name_token, "cannot test a {s}", .{
......@@ -4836,12 +4797,11 @@ fn testDecl(
48364797 }),
48374798 });
48384799 }
4839 s = local_ptr.parent;
4800 continue :find_scope local_ptr.parent.unwrap();
48404801 },
4841 .gen_zir => s = s.cast(GenZir).?.parent,
4842 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4843 .namespace => {
4844 const ns = s.cast(Scope.Namespace).?;
4802 .gen_zir => |gen_zir| continue :find_scope gen_zir.parent.unwrap(),
4803 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
4804 .namespace => |ns| {
48454805 if (ns.decls.get(name_str_index)) |i| {
48464806 if (found_already) |f| {
48474807 return astgen.failTokNotes(test_name_token, "ambiguous reference", .{}, &.{
......@@ -4854,10 +4814,10 @@ fn testDecl(
48544814 }
48554815 num_namespaces_out += 1;
48564816 capturing_namespace = ns;
4857 s = ns.parent;
4817 continue :find_scope ns.parent.unwrap();
48584818 },
4859 .top => break,
4860 };
4819 .top => break :find_scope,
4820 }
48614821 if (found_already == null) {
48624822 const ident_name = try astgen.identifierTokenString(test_name_token);
48634823 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
......@@ -8409,7 +8369,6 @@ fn localVarRef(
84098369) InnerError!Zir.Inst.Ref {
84108370 const astgen = gz.astgen;
84118371 const name_str_index = try astgen.identAsString(ident_token);
8412 var s = scope;
84138372 var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
84148373 var found_needs_tunnel: bool = undefined; // defined when `found_already != null`
84158374 var found_namespaces_out: u32 = undefined; // defined when `found_already != null`
......@@ -8419,10 +8378,8 @@ fn localVarRef(
84198378 // defined by `num_namespaces_out != 0`
84208379 var capturing_namespace: *Scope.Namespace = undefined;
84218380
8422 while (true) switch (s.tag) {
8423 .local_val => {
8424 const local_val = s.cast(Scope.LocalVal).?;
8425
8381 find_scope: switch (scope.unwrap()) {
8382 .local_val => |local_val| {
84268383 if (local_val.name == name_str_index) {
84278384 // Locals cannot shadow anything, so we do not need to look for ambiguous
84288385 // references in this case.
......@@ -8445,10 +8402,9 @@ fn localVarRef(
84458402
84468403 return rvalueNoCoercePreRef(gz, ri, value_inst, ident);
84478404 }
8448 s = local_val.parent;
8405 continue :find_scope local_val.parent.unwrap();
84498406 },
8450 .local_ptr => {
8451 const local_ptr = s.cast(Scope.LocalPtr).?;
8407 .local_ptr => |local_ptr| {
84528408 if (local_ptr.name == name_str_index) {
84538409 if (ri.rl == .discard and ri.ctx == .assignment) {
84548410 local_ptr.discarded = .fromToken(ident_token);
......@@ -8497,12 +8453,11 @@ fn localVarRef(
84978453 },
84988454 }
84998455 }
8500 s = local_ptr.parent;
8456 continue :find_scope local_ptr.parent.unwrap();
85018457 },
8502 .gen_zir => s = s.cast(GenZir).?.parent,
8503 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
8504 .namespace => {
8505 const ns = s.cast(Scope.Namespace).?;
8458 .gen_zir => |gen_zir| continue :find_scope gen_zir.parent.unwrap(),
8459 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
8460 .namespace => |ns| {
85068461 if (ns.decls.get(name_str_index)) |i| {
85078462 if (found_already) |f| {
85088463 return astgen.failNodeNotes(ident, "ambiguous reference", .{}, &.{
......@@ -8517,10 +8472,10 @@ fn localVarRef(
85178472 }
85188473 num_namespaces_out += 1;
85198474 capturing_namespace = ns;
8520 s = ns.parent;
8475 continue :find_scope ns.parent.unwrap();
85218476 },
8522 .top => break,
8523 };
8477 .top => break :find_scope,
8478 }
85248479 if (found_already == null) {
85258480 const ident_name = try astgen.identifierTokenString(ident_token);
85268481 return astgen.failNode(ident, "use of undeclared identifier '{s}'", .{ident_name});
......@@ -11812,6 +11767,26 @@ const Scope = struct {
1181211767 };
1181311768 }
1181411769
11770 fn unwrap(base: *Scope) Unwrapped {
11771 return switch (base.tag) {
11772 inline else => |tag| @unionInit(
11773 Unwrapped,
11774 @tagName(tag),
11775 @alignCast(@fieldParentPtr("base", base)),
11776 ),
11777 };
11778 }
11779
11780 const Unwrapped = union(Tag) {
11781 gen_zir: *GenZir,
11782 local_val: *LocalVal,
11783 local_ptr: *LocalPtr,
11784 defer_normal: *Defer,
11785 defer_error: *Defer,
11786 namespace: *Namespace,
11787 top: *Top,
11788 };
11789
1181511790 const Tag = enum {
1181611791 gen_zir,
1181711792 local_val,
......@@ -13408,11 +13383,9 @@ fn detectLocalShadowing(
1340813383 });
1340913384 }
1341013385
13411 var s = scope;
1341213386 var outer_scope = false;
13413 while (true) switch (s.tag) {
13414 .local_val => {
13415 const local_val = s.cast(Scope.LocalVal).?;
13387 find_scope: switch (scope.unwrap()) {
13388 .local_val => |local_val| {
1341613389 if (local_val.name == ident_name) {
1341713390 const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
1341813391 const name = try gpa.dupe(u8, name_slice);
......@@ -13438,10 +13411,9 @@ fn detectLocalShadowing(
1343813411 ),
1343913412 });
1344013413 }
13441 s = local_val.parent;
13414 continue :find_scope local_val.parent.unwrap();
1344213415 },
13443 .local_ptr => {
13444 const local_ptr = s.cast(Scope.LocalPtr).?;
13416 .local_ptr => |local_ptr| {
1344513417 if (local_ptr.name == ident_name) {
1344613418 const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
1344713419 const name = try gpa.dupe(u8, name_slice);
......@@ -13467,14 +13439,12 @@ fn detectLocalShadowing(
1346713439 ),
1346813440 });
1346913441 }
13470 s = local_ptr.parent;
13442 continue :find_scope local_ptr.parent.unwrap();
1347113443 },
13472 .namespace => {
13444 .namespace => |ns| {
1347313445 outer_scope = true;
13474 const ns = s.cast(Scope.Namespace).?;
1347513446 const decl_node = ns.decls.get(ident_name) orelse {
13476 s = ns.parent;
13477 continue;
13447 continue :find_scope ns.parent.unwrap();
1347813448 };
1347913449 const name_slice = mem.span(astgen.nullTerminatedString(ident_name));
1348013450 const name = try gpa.dupe(u8, name_slice);
......@@ -13485,13 +13455,13 @@ fn detectLocalShadowing(
1348513455 try astgen.errNoteNode(decl_node, "declared here", .{}),
1348613456 });
1348713457 },
13488 .gen_zir => {
13489 s = s.cast(GenZir).?.parent;
13458 .gen_zir => |gen_zir| {
1349013459 outer_scope = true;
13460 continue :find_scope gen_zir.parent.unwrap();
1349113461 },
13492 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
13493 .top => break,
13494 };
13462 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
13463 .top => break :find_scope,
13464 }
1349513465}
1349613466
1349713467const LineColumn = struct { u32, u32 };
......@@ -13728,10 +13698,8 @@ fn scanContainer(
1372813698 continue;
1372913699 }
1373013700
13731 var s = namespace.parent;
13732 while (true) switch (s.tag) {
13733 .local_val => {
13734 const local_val = s.cast(Scope.LocalVal).?;
13701 find_scope: switch (namespace.parent.unwrap()) {
13702 .local_val => |local_val| {
1373513703 if (local_val.name == name_str_index) {
1373613704 try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{
1373713705 token_bytes, @tagName(local_val.id_cat),
......@@ -13743,12 +13711,11 @@ fn scanContainer(
1374313711 ),
1374413712 });
1374513713 any_invalid_declarations = true;
13746 break;
13714 break :find_scope;
1374713715 }
13748 s = local_val.parent;
13716 continue :find_scope local_val.parent.unwrap();
1374913717 },
13750 .local_ptr => {
13751 const local_ptr = s.cast(Scope.LocalPtr).?;
13718 .local_ptr => |local_ptr| {
1375213719 if (local_ptr.name == name_str_index) {
1375313720 try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{
1375413721 token_bytes, @tagName(local_ptr.id_cat),
......@@ -13760,15 +13727,15 @@ fn scanContainer(
1376013727 ),
1376113728 });
1376213729 any_invalid_declarations = true;
13763 break;
13730 break :find_scope;
1376413731 }
13765 s = local_ptr.parent;
13732 continue :find_scope local_ptr.parent.unwrap();
1376613733 },
13767 .namespace => s = s.cast(Scope.Namespace).?.parent,
13768 .gen_zir => s = s.cast(GenZir).?.parent,
13769 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
13770 .top => break,
13771 };
13734 .namespace => |ns| continue :find_scope ns.parent.unwrap(),
13735 .gen_zir => |gen_zir| continue :find_scope gen_zir.parent.unwrap(),
13736 .defer_normal, .defer_error => |defer_scope| continue :find_scope defer_scope.parent.unwrap(),
13737 .top => break :find_scope,
13738 }
1377213739 }
1377313740
1377413741 if (!any_duplicates) {