| ... | @@ -7017,8 +7017,7 @@ fn switchExprErrUnion( | ... | @@ -7017,8 +7017,7 @@ fn switchExprErrUnion( |
| 7017 | const case_slice = case_scope.instructionsSlice(); | 7017 | const case_slice = case_scope.instructionsSlice(); |
| 7018 | // Since we use the switch_block_err_union instruction itself to refer | 7018 | // Since we use the switch_block_err_union instruction itself to refer |
| 7019 | // to the capture, which will not be added to the child block, we need | 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 | 7020 | // to handle ref_table manually. |
| 7021 | // capture instruction. | | |
| 7022 | const refs_len = refs: { | 7021 | const refs_len = refs: { |
| 7023 | var n: usize = 0; | 7022 | var n: usize = 0; |
| 7024 | var check_inst = switch_block; | 7023 | var check_inst = switch_block; |
| ... | @@ -7054,9 +7053,24 @@ fn switchExprErrUnion( | ... | @@ -7054,9 +7053,24 @@ fn switchExprErrUnion( |
| 7054 | break :blk .{ err_name, error_payload }; | 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 | // In this pass we generate all the item and prong expressions for error cases. | 7070 | // In this pass we generate all the item and prong expressions for error cases. |
| 7058 | var multi_case_index: u32 = 0; | 7071 | var multi_case_index: u32 = 0; |
| 7059 | var scalar_case_index: u32 = 0; | 7072 | var scalar_case_index: u32 = 0; |
| | 7073 | var any_uses_err_capture = false; |
| 7060 | for (case_nodes) |case_node| { | 7074 | for (case_nodes) |case_node| { |
| 7061 | const case = tree.fullSwitchCase(case_node).?; | 7075 | const case = tree.fullSwitchCase(case_node).?; |
| 7062 | | 7076 | |
| ... | @@ -7066,31 +7080,42 @@ fn switchExprErrUnion( | ... | @@ -7066,31 +7080,42 @@ fn switchExprErrUnion( |
| 7066 | var dbg_var_name: ?u32 = null; | 7080 | var dbg_var_name: ?u32 = null; |
| 7067 | var dbg_var_inst: Zir.Inst.Ref = undefined; | 7081 | var dbg_var_inst: Zir.Inst.Ref = undefined; |
| 7068 | var err_scope: Scope.LocalVal = undefined; | 7082 | var err_scope: Scope.LocalVal = undefined; |
| 7069 | var tag_scope: Scope.LocalVal = undefined; | 7083 | var capture_scope: Scope.LocalVal = undefined; |
| 7070 | | 7084 | |
| 7071 | const sub_scope = blk: { | 7085 | const sub_scope = blk: { |
| 7072 | const tag_token = case.payload_token orelse break :blk &case_scope.base; | 7086 | err_scope = .{ |
| 7073 | assert(token_tags[tag_token] == .identifier); | 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); | 7095 | const capture_token = case.payload_token orelse break :blk &err_scope.base; |
| 7076 | if (mem.eql(u8, tag_slice, "_")) { | 7096 | assert(token_tags[capture_token] == .identifier); |
| 7077 | return astgen.failTok(tag_token, "discard of error capture; omit it instead", .{}); | 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); | 7102 | const tag_name = try astgen.identAsString(capture_token); |
| 7080 | try astgen.detectLocalShadowing(&case_scope.base, tag_name, tag_token, tag_slice, .capture); | 7103 | try astgen.detectLocalShadowing(&case_scope.base, tag_name, capture_token, capture_slice, .capture); |
| 7081 | | 7104 | |
| 7082 | tag_scope = .{ | 7105 | capture_scope = .{ |
| 7083 | .parent = &case_scope.base, | 7106 | .parent = &case_scope.base, |
| 7084 | .gen_zir = &case_scope, | 7107 | .gen_zir = &case_scope, |
| 7085 | .name = tag_name, | 7108 | .name = tag_name, |
| 7086 | .inst = switch_block.toRef(), | 7109 | .inst = switch_block.toRef(), |
| 7087 | .token_src = tag_token, | 7110 | .token_src = capture_token, |
| 7088 | .id_cat = .capture, | 7111 | .id_cat = .capture, |
| 7089 | }; | 7112 | }; |
| 7090 | dbg_var_name = tag_name; | 7113 | dbg_var_name = tag_name; |
| 7091 | dbg_var_inst = switch_block.toRef(); | 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 | const header_index: u32 = @intCast(payloads.items.len); | 7121 | const header_index: u32 = @intCast(payloads.items.len); |
| ... | @@ -7144,34 +7169,28 @@ fn switchExprErrUnion( | ... | @@ -7144,34 +7169,28 @@ fn switchExprErrUnion( |
| 7144 | case_scope.instructions_top = parent_gz.instructions.items.len; | 7169 | case_scope.instructions_top = parent_gz.instructions.items.len; |
| 7145 | defer case_scope.unstack(); | 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 | try case_scope.addDbgBlockBegin(); | 7172 | try case_scope.addDbgBlockBegin(); |
| 7158 | if (dbg_var_name) |some| { | 7173 | if (dbg_var_name) |some| { |
| 7159 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); | 7174 | try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); |
| 7160 | } | 7175 | } |
| 7161 | const target_expr_node = case.ast.target_expr; | 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); | 7177 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node); |
| 7163 | // check sub_scope, not err_scope to avoid false positive unused error capture | 7178 | // check capture_scope, not err_scope to avoid false positive unused error capture |
| 7164 | try checkUsed(parent_gz, &case_scope.base, sub_scope); | 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 | try case_scope.addDbgBlockEnd(); | 7185 | try case_scope.addDbgBlockEnd(); |
| 7166 | if (!parent_gz.refIsNoReturn(case_result)) { | 7186 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 7167 | _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node); | 7187 | _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node); |
| 7168 | } | 7188 | } |
| 7169 | | 7189 | |
| 7170 | const case_slice = case_scope.instructionsSlice(); | 7190 | const case_slice = case_scope.instructionsSlice(); |
| 7171 | // Since we use the switch_block instruction itself to refer to the | 7191 | // Since we use the switch_block_err_union instruction itself to refer |
| 7172 | // capture, which will not be added to the child block, we need to | 7192 | // to the capture, which will not be added to the child block, we need |
| 7173 | // handle ref_table manually, and the same for the inline tag | 7193 | // to handle ref_table manually. |
| 7174 | // capture instruction. | | |
| 7175 | const refs_len = refs: { | 7194 | const refs_len = refs: { |
| 7176 | var n: usize = 0; | 7195 | var n: usize = 0; |
| 7177 | var check_inst = switch_block; | 7196 | var check_inst = switch_block; |
| ... | @@ -7179,6 +7198,13 @@ fn switchExprErrUnion( | ... | @@ -7179,6 +7198,13 @@ fn switchExprErrUnion( |
| 7179 | n += 1; | 7198 | n += 1; |
| 7180 | check_inst = ref_inst; | 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 | break :refs n; | 7208 | break :refs n; |
| 7183 | }; | 7209 | }; |
| 7184 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); | 7210 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); |
| ... | @@ -7192,6 +7218,11 @@ fn switchExprErrUnion( | ... | @@ -7192,6 +7218,11 @@ fn switchExprErrUnion( |
| 7192 | if (astgen.ref_table.fetchRemove(switch_block)) |kv| { | 7218 | if (astgen.ref_table.fetchRemove(switch_block)) |kv| { |
| 7193 | appendPossiblyRefdBodyInst(astgen, payloads, kv.value); | 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 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); | 7226 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); |
| 7196 | } | 7227 | } |
| 7197 | } | 7228 | } |
| ... | @@ -7209,6 +7240,7 @@ fn switchExprErrUnion( | ... | @@ -7209,6 +7240,7 @@ fn switchExprErrUnion( |
| 7209 | .has_multi_cases = multi_cases_len != 0, | 7240 | .has_multi_cases = multi_cases_len != 0, |
| 7210 | .has_else = has_else, | 7241 | .has_else = has_else, |
| 7211 | .scalar_cases_len = @intCast(scalar_cases_len), | 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,6 +7248,10 @@ fn switchExprErrUnion( |
| 7216 | astgen.extra.appendAssumeCapacity(multi_cases_len); | 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 | const zir_datas = astgen.instructions.items(.data); | 7255 | const zir_datas = astgen.instructions.items(.data); |
| 7220 | zir_datas[@intFromEnum(switch_block)].pl_node.payload_index = payload_index; | 7256 | zir_datas[@intFromEnum(switch_block)].pl_node.payload_index = payload_index; |
| 7221 | | 7257 | |