| ... | ... | @@ -7017,8 +7017,7 @@ fn switchExprErrUnion( |
| 7017 | 7017 | const case_slice = case_scope.instructionsSlice(); |
| 7018 | 7018 | // Since we use the switch_block_err_union instruction itself to refer |
| 7019 | 7019 | // to the capture, which will not be added to the child block, we need |
| 7020 | | // to handle ref_table manually, and the same for the inline tag |
| 7021 | | // capture instruction. |
| 7020 | // to handle ref_table manually. |
| 7022 | 7021 | const refs_len = refs: { |
| 7023 | 7022 | var n: usize = 0; |
| 7024 | 7023 | var check_inst = switch_block; |
| ... | ... | @@ -7054,9 +7053,24 @@ fn switchExprErrUnion( |
| 7054 | 7053 | break :blk .{ err_name, error_payload }; |
| 7055 | 7054 | }; |
| 7056 | 7055 | |
| 7056 | // allocate a shared dummy instruction for the error capture |
| 7057 | const err_inst = err_inst: { |
| 7058 | const inst: Zir.Inst.Index = @enumFromInt(astgen.instructions.len); |
| 7059 | try astgen.instructions.append(astgen.gpa, .{ |
| 7060 | .tag = .extended, |
| 7061 | .data = .{ .extended = .{ |
| 7062 | .opcode = .value_placeholder, |
| 7063 | .small = undefined, |
| 7064 | .operand = undefined, |
| 7065 | } }, |
| 7066 | }); |
| 7067 | break :err_inst inst; |
| 7068 | }; |
| 7069 | |
| 7057 | 7070 | // In this pass we generate all the item and prong expressions for error cases. |
| 7058 | 7071 | var multi_case_index: u32 = 0; |
| 7059 | 7072 | var scalar_case_index: u32 = 0; |
| 7073 | var any_uses_err_capture = false; |
| 7060 | 7074 | for (case_nodes) |case_node| { |
| 7061 | 7075 | const case = tree.fullSwitchCase(case_node).?; |
| 7062 | 7076 | |
| ... | ... | @@ -7066,31 +7080,42 @@ fn switchExprErrUnion( |
| 7066 | 7080 | var dbg_var_name: ?u32 = null; |
| 7067 | 7081 | var dbg_var_inst: Zir.Inst.Ref = undefined; |
| 7068 | 7082 | var err_scope: Scope.LocalVal = undefined; |
| 7069 | | var tag_scope: Scope.LocalVal = undefined; |
| 7083 | var capture_scope: Scope.LocalVal = undefined; |
| 7070 | 7084 | |
| 7071 | 7085 | const sub_scope = blk: { |
| 7072 | | const tag_token = case.payload_token orelse break :blk &case_scope.base; |
| 7073 | | assert(token_tags[tag_token] == .identifier); |
| 7086 | err_scope = .{ |
| 7087 | .parent = &case_scope.base, |
| 7088 | .gen_zir = &case_scope, |
| 7089 | .name = err_name, |
| 7090 | .inst = err_inst.toRef(), |
| 7091 | .token_src = error_payload, |
| 7092 | .id_cat = .capture, |
| 7093 | }; |
| 7074 | 7094 | |
| 7075 | | const tag_slice = tree.tokenSlice(tag_token); |
| 7076 | | if (mem.eql(u8, tag_slice, "_")) { |
| 7077 | | return astgen.failTok(tag_token, "discard of error capture; omit it instead", .{}); |
| 7095 | const capture_token = case.payload_token orelse break :blk &err_scope.base; |
| 7096 | assert(token_tags[capture_token] == .identifier); |
| 7097 | |
| 7098 | const capture_slice = tree.tokenSlice(capture_token); |
| 7099 | if (mem.eql(u8, capture_slice, "_")) { |
| 7100 | return astgen.failTok(capture_token, "discard of error capture; omit it instead", .{}); |
| 7078 | 7101 | } |
| 7079 | | const tag_name = try astgen.identAsString(tag_token); |
| 7080 | | try astgen.detectLocalShadowing(&case_scope.base, tag_name, tag_token, tag_slice, .capture); |
| 7102 | const tag_name = try astgen.identAsString(capture_token); |
| 7103 | try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture); |
| 7081 | 7104 | |
| 7082 | | tag_scope = .{ |
| 7105 | capture_scope = .{ |
| 7083 | 7106 | .parent = &case_scope.base, |
| 7084 | 7107 | .gen_zir = &case_scope, |
| 7085 | 7108 | .name = tag_name, |
| 7086 | 7109 | .inst = switch_block.toRef(), |
| 7087 | | .token_src = tag_token, |
| 7110 | .token_src = capture_token, |
| 7088 | 7111 | .id_cat = .capture, |
| 7089 | 7112 | }; |
| 7090 | 7113 | dbg_var_name = tag_name; |
| 7091 | 7114 | dbg_var_inst = switch_block.toRef(); |
| 7092 | 7115 | |
| 7093 | | break :blk &tag_scope.base; |
| 7116 | err_scope.parent = &capture_scope.base; |
| 7117 | |
| 7118 | break :blk &err_scope.base; |
| 7094 | 7119 | }; |
| 7095 | 7120 | |
| 7096 | 7121 | const header_index: u32 = @intCast(payloads.items.len); |
| ... | ... | @@ -7144,34 +7169,28 @@ fn switchExprErrUnion( |
| 7144 | 7169 | case_scope.instructions_top = parent_gz.instructions.items.len; |
| 7145 | 7170 | defer case_scope.unstack(); |
| 7146 | 7171 | |
| 7147 | | const err_code_inst = try case_scope.addUnNode(.err_union_code, raw_operand, operand_node); |
| 7148 | | err_scope = .{ |
| 7149 | | .parent = sub_scope, |
| 7150 | | .gen_zir = &case_scope, |
| 7151 | | .name = err_name, |
| 7152 | | .inst = err_code_inst, |
| 7153 | | .token_src = error_payload, |
| 7154 | | .id_cat = .capture, |
| 7155 | | }; |
| 7156 | | |
| 7157 | 7172 | try case_scope.addDbgBlockBegin(); |
| 7158 | 7173 | if (dbg_var_name) |some| { |
| 7159 | 7174 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); |
| 7160 | 7175 | } |
| 7161 | 7176 | const target_expr_node = case.ast.target_expr; |
| 7162 | | const case_result = try expr(&case_scope, &err_scope.base, block_scope.break_result_info, target_expr_node); |
| 7163 | | // check sub_scope, not err_scope to avoid false positive unused error capture |
| 7164 | | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 7177 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node); |
| 7178 | // check capture_scope, not err_scope to avoid false positive unused error capture |
| 7179 | try checkUsed(parent_gz, &case_scope.base, err_scope.parent); |
| 7180 | const uses_err = err_scope.used != 0 or err_scope.discarded != 0; |
| 7181 | if (uses_err) { |
| 7182 | try case_scope.addDbgVar(.dbg_var_val, err_name, err_inst.toRef()); |
| 7183 | any_uses_err_capture = true; |
| 7184 | } |
| 7165 | 7185 | try case_scope.addDbgBlockEnd(); |
| 7166 | 7186 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 7167 | 7187 | _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node); |
| 7168 | 7188 | } |
| 7169 | 7189 | |
| 7170 | 7190 | const case_slice = case_scope.instructionsSlice(); |
| 7171 | | // Since we use the switch_block instruction itself to refer to the |
| 7172 | | // capture, which will not be added to the child block, we need to |
| 7173 | | // handle ref_table manually, and the same for the inline tag |
| 7174 | | // capture instruction. |
| 7191 | // Since we use the switch_block_err_union instruction itself to refer |
| 7192 | // to the capture, which will not be added to the child block, we need |
| 7193 | // to handle ref_table manually. |
| 7175 | 7194 | const refs_len = refs: { |
| 7176 | 7195 | var n: usize = 0; |
| 7177 | 7196 | var check_inst = switch_block; |
| ... | ... | @@ -7179,6 +7198,13 @@ fn switchExprErrUnion( |
| 7179 | 7198 | n += 1; |
| 7180 | 7199 | check_inst = ref_inst; |
| 7181 | 7200 | } |
| 7201 | if (uses_err) { |
| 7202 | check_inst = err_inst; |
| 7203 | while (astgen.ref_table.get(check_inst)) |ref_inst| { |
| 7204 | n += 1; |
| 7205 | check_inst = ref_inst; |
| 7206 | } |
| 7207 | } |
| 7182 | 7208 | break :refs n; |
| 7183 | 7209 | }; |
| 7184 | 7210 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); |
| ... | ... | @@ -7192,6 +7218,11 @@ fn switchExprErrUnion( |
| 7192 | 7218 | if (astgen.ref_table.fetchRemove(switch_block)) |kv| { |
| 7193 | 7219 | appendPossiblyRefdBodyInst(astgen, payloads, kv.value); |
| 7194 | 7220 | } |
| 7221 | if (uses_err) { |
| 7222 | if (astgen.ref_table.fetchRemove(err_inst)) |kv| { |
| 7223 | appendPossiblyRefdBodyInst(astgen, payloads, kv.value); |
| 7224 | } |
| 7225 | } |
| 7195 | 7226 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); |
| 7196 | 7227 | } |
| 7197 | 7228 | } |
| ... | ... | @@ -7209,6 +7240,7 @@ fn switchExprErrUnion( |
| 7209 | 7240 | .has_multi_cases = multi_cases_len != 0, |
| 7210 | 7241 | .has_else = has_else, |
| 7211 | 7242 | .scalar_cases_len = @intCast(scalar_cases_len), |
| 7243 | .any_uses_err_capture = any_uses_err_capture, |
| 7212 | 7244 | }, |
| 7213 | 7245 | }); |
| 7214 | 7246 | |
| ... | ... | @@ -7216,6 +7248,10 @@ fn switchExprErrUnion( |
| 7216 | 7248 | astgen.extra.appendAssumeCapacity(multi_cases_len); |
| 7217 | 7249 | } |
| 7218 | 7250 | |
| 7251 | if (any_uses_err_capture) { |
| 7252 | astgen.extra.appendAssumeCapacity(@intFromEnum(err_inst)); |
| 7253 | } |
| 7254 | |
| 7219 | 7255 | const zir_datas = astgen.instructions.items(.data); |
| 7220 | 7256 | zir_datas[@intFromEnum(switch_block)].pl_node.payload_index = payload_index; |
| 7221 | 7257 | |