| ... | ... | @@ -839,7 +839,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 839 | 839 | |
| 840 | 840 | .if_simple, |
| 841 | 841 | .@"if", |
| 842 | | => return ifExpr(gz, scope, ri.br(), node, tree.fullIf(node).?), |
| 842 | => { |
| 843 | const if_full = tree.fullIf(node).?; |
| 844 | if (if_full.error_token) |error_token| { |
| 845 | const tag = node_tags[if_full.ast.else_expr]; |
| 846 | if ((tag == .@"switch" or tag == .switch_comma) and |
| 847 | std.mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(error_token + 4))) |
| 848 | { |
| 849 | return switchExprErrUnion(gz, scope, ri.br(), node, .@"if"); |
| 850 | } |
| 851 | } |
| 852 | return ifExpr(gz, scope, ri.br(), node, if_full); |
| 853 | }, |
| 843 | 854 | |
| 844 | 855 | .while_simple, |
| 845 | 856 | .while_cont, |
| ... | ... | @@ -1020,7 +1031,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 1020 | 1031 | token_tags[catch_token + 4] == .keyword_switch) |
| 1021 | 1032 | { |
| 1022 | 1033 | if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) { |
| 1023 | | return switchExprErrUnion(gz, scope, ri.br(), node); |
| 1034 | return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch"); |
| 1024 | 1035 | } |
| 1025 | 1036 | } |
| 1026 | 1037 | break :blk catch_token + 2; |
| ... | ... | @@ -6869,7 +6880,8 @@ fn switchExprErrUnion( |
| 6869 | 6880 | parent_gz: *GenZir, |
| 6870 | 6881 | scope: *Scope, |
| 6871 | 6882 | ri: ResultInfo, |
| 6872 | | catch_node: Ast.Node.Index, |
| 6883 | catch_or_if_node: Ast.Node.Index, |
| 6884 | node_ty: enum { @"catch", @"if" }, |
| 6873 | 6885 | ) InnerError!Zir.Inst.Ref { |
| 6874 | 6886 | const astgen = parent_gz.astgen; |
| 6875 | 6887 | const gpa = astgen.gpa; |
| ... | ... | @@ -6878,21 +6890,42 @@ fn switchExprErrUnion( |
| 6878 | 6890 | const node_tags = tree.nodes.items(.tag); |
| 6879 | 6891 | const main_tokens = tree.nodes.items(.main_token); |
| 6880 | 6892 | const token_tags = tree.tokens.items(.tag); |
| 6881 | | const operand_node = node_datas[catch_node].lhs; |
| 6882 | | const switch_node = node_datas[catch_node].rhs; |
| 6893 | |
| 6894 | const if_full = switch (node_ty) { |
| 6895 | .@"catch" => undefined, |
| 6896 | .@"if" => tree.fullIf(catch_or_if_node).?, |
| 6897 | }; |
| 6898 | |
| 6899 | const switch_node, const operand_node, const error_payload = switch (node_ty) { |
| 6900 | .@"catch" => .{ |
| 6901 | node_datas[catch_or_if_node].rhs, |
| 6902 | node_datas[catch_or_if_node].lhs, |
| 6903 | main_tokens[catch_or_if_node] + 2, |
| 6904 | }, |
| 6905 | .@"if" => .{ |
| 6906 | if_full.ast.else_expr, |
| 6907 | if_full.ast.cond_expr, |
| 6908 | if_full.error_token.?, |
| 6909 | }, |
| 6910 | }; |
| 6911 | assert(node_tags[switch_node] == .@"switch" or node_tags[switch_node] == .switch_comma); |
| 6912 | |
| 6883 | 6913 | const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); |
| 6884 | 6914 | const case_nodes = tree.extra_data[extra.start..extra.end]; |
| 6885 | 6915 | |
| 6886 | | const need_rl = astgen.nodes_need_rl.contains(catch_node); |
| 6916 | const need_rl = astgen.nodes_need_rl.contains(catch_or_if_node); |
| 6887 | 6917 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 6888 | 6918 | .rl = switch (ri.rl) { |
| 6889 | | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, catch_node)).? }, |
| 6919 | .ptr => .{ .ty = (try ri.rl.resultType(parent_gz, catch_or_if_node)).? }, |
| 6890 | 6920 | .inferred_ptr => .none, |
| 6891 | 6921 | else => ri.rl, |
| 6892 | 6922 | }, |
| 6893 | 6923 | .ctx = ri.ctx, |
| 6894 | 6924 | }; |
| 6895 | 6925 | |
| 6926 | const payload_is_ref = node_ty == .@"if" and |
| 6927 | if_full.payload_token != null and token_tags[if_full.payload_token.?] == .asterisk; |
| 6928 | |
| 6896 | 6929 | // We need to call `rvalue` to write through to the pointer only if we had a |
| 6897 | 6930 | // result pointer and aren't forwarding it. |
| 6898 | 6931 | const LocTag = @typeInfo(ResultInfo.Loc).Union.tag_type.?; |
| ... | ... | @@ -6960,12 +6993,15 @@ fn switchExprErrUnion( |
| 6960 | 6993 | } |
| 6961 | 6994 | } |
| 6962 | 6995 | |
| 6963 | | const operand_ri: ResultInfo = .{ .rl = .none, .ctx = .error_handling_expr }; |
| 6996 | const operand_ri: ResultInfo = .{ |
| 6997 | .rl = if (payload_is_ref) .ref else .none, |
| 6998 | .ctx = .error_handling_expr, |
| 6999 | }; |
| 6964 | 7000 | |
| 6965 | 7001 | astgen.advanceSourceCursorToNode(operand_node); |
| 6966 | 7002 | const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; |
| 6967 | 7003 | |
| 6968 | | const raw_operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, node_datas[catch_node].rhs); |
| 7004 | const raw_operand = try reachableExpr(parent_gz, scope, operand_ri, operand_node, switch_node); |
| 6969 | 7005 | const item_ri: ResultInfo = .{ .rl = .none }; |
| 6970 | 7006 | |
| 6971 | 7007 | // This contains the data that goes into the `extra` array for the SwitchBlockErrUnion, except |
| ... | ... | @@ -7006,13 +7042,93 @@ fn switchExprErrUnion( |
| 7006 | 7042 | |
| 7007 | 7043 | try case_scope.addDbgBlockBegin(); |
| 7008 | 7044 | |
| 7009 | | const unwrapped_payload = try case_scope.addUnNode(.err_union_payload_unsafe, raw_operand, catch_node); |
| 7010 | | const case_result = switch (ri.rl) { |
| 7011 | | .ref, .ref_coerced_ty => unwrapped_payload, |
| 7012 | | else => try rvalue(&case_scope, block_scope.break_result_info, unwrapped_payload, catch_node), |
| 7013 | | }; |
| 7014 | | try case_scope.addDbgBlockEnd(); |
| 7015 | | _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, catch_node); |
| 7045 | const unwrap_payload_tag: Zir.Inst.Tag = if (payload_is_ref) |
| 7046 | .err_union_payload_unsafe_ptr |
| 7047 | else |
| 7048 | .err_union_payload_unsafe; |
| 7049 | |
| 7050 | const unwrapped_payload = try case_scope.addUnNode( |
| 7051 | unwrap_payload_tag, |
| 7052 | raw_operand, |
| 7053 | catch_or_if_node, |
| 7054 | ); |
| 7055 | |
| 7056 | switch (node_ty) { |
| 7057 | .@"catch" => { |
| 7058 | const case_result = switch (ri.rl) { |
| 7059 | .ref, .ref_coerced_ty => unwrapped_payload, |
| 7060 | else => try rvalue( |
| 7061 | &case_scope, |
| 7062 | block_scope.break_result_info, |
| 7063 | unwrapped_payload, |
| 7064 | catch_or_if_node, |
| 7065 | ), |
| 7066 | }; |
| 7067 | try case_scope.addDbgBlockEnd(); |
| 7068 | _ = try case_scope.addBreakWithSrcNode( |
| 7069 | .@"break", |
| 7070 | switch_block, |
| 7071 | case_result, |
| 7072 | catch_or_if_node, |
| 7073 | ); |
| 7074 | }, |
| 7075 | .@"if" => { |
| 7076 | var payload_val_scope: Scope.LocalVal = undefined; |
| 7077 | |
| 7078 | try case_scope.addDbgBlockBegin(); |
| 7079 | const then_node = if_full.ast.then_expr; |
| 7080 | const then_sub_scope = s: { |
| 7081 | assert(if_full.error_token != null); |
| 7082 | if (if_full.payload_token) |payload_token| { |
| 7083 | const token_name_index = payload_token + @intFromBool(payload_is_ref); |
| 7084 | const ident_name = try astgen.identAsString(token_name_index); |
| 7085 | const token_name_str = tree.tokenSlice(token_name_index); |
| 7086 | if (mem.eql(u8, "_", token_name_str)) |
| 7087 | break :s &case_scope.base; |
| 7088 | try astgen.detectLocalShadowing( |
| 7089 | &case_scope.base, |
| 7090 | ident_name, |
| 7091 | token_name_index, |
| 7092 | token_name_str, |
| 7093 | .capture, |
| 7094 | ); |
| 7095 | payload_val_scope = .{ |
| 7096 | .parent = &case_scope.base, |
| 7097 | .gen_zir = &case_scope, |
| 7098 | .name = ident_name, |
| 7099 | .inst = unwrapped_payload, |
| 7100 | .token_src = payload_token, |
| 7101 | .id_cat = .capture, |
| 7102 | }; |
| 7103 | try case_scope.addDbgVar(.dbg_var_val, ident_name, unwrapped_payload); |
| 7104 | break :s &payload_val_scope.base; |
| 7105 | } else { |
| 7106 | _ = try case_scope.addUnNode( |
| 7107 | .ensure_err_union_payload_void, |
| 7108 | raw_operand, |
| 7109 | catch_or_if_node, |
| 7110 | ); |
| 7111 | break :s &case_scope.base; |
| 7112 | } |
| 7113 | }; |
| 7114 | const then_result = try expr( |
| 7115 | &case_scope, |
| 7116 | then_sub_scope, |
| 7117 | block_scope.break_result_info, |
| 7118 | then_node, |
| 7119 | ); |
| 7120 | try checkUsed(parent_gz, &case_scope.base, then_sub_scope); |
| 7121 | if (!case_scope.endsWithNoReturn()) { |
| 7122 | try case_scope.addDbgBlockEnd(); |
| 7123 | _ = try case_scope.addBreakWithSrcNode( |
| 7124 | .@"break", |
| 7125 | switch_block, |
| 7126 | then_result, |
| 7127 | then_node, |
| 7128 | ); |
| 7129 | } |
| 7130 | }, |
| 7131 | } |
| 7016 | 7132 | |
| 7017 | 7133 | const case_slice = case_scope.instructionsSlice(); |
| 7018 | 7134 | // Since we use the switch_block_err_union instruction itself to refer |
| ... | ... | @@ -7029,9 +7145,18 @@ fn switchExprErrUnion( |
| 7029 | 7145 | }; |
| 7030 | 7146 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); |
| 7031 | 7147 | try payloads.ensureUnusedCapacity(gpa, body_len); |
| 7148 | const capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = switch (node_ty) { |
| 7149 | .@"catch" => .none, |
| 7150 | .@"if" => if (if_full.payload_token == null) |
| 7151 | .none |
| 7152 | else if (payload_is_ref) |
| 7153 | .by_ref |
| 7154 | else |
| 7155 | .by_val, |
| 7156 | }; |
| 7032 | 7157 | payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{ |
| 7033 | 7158 | .body_len = @intCast(body_len), |
| 7034 | | .capture = .none, |
| 7159 | .capture = capture, |
| 7035 | 7160 | .is_inline = false, |
| 7036 | 7161 | .has_tag_capture = false, |
| 7037 | 7162 | }); |
| ... | ... | @@ -7041,8 +7166,7 @@ fn switchExprErrUnion( |
| 7041 | 7166 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); |
| 7042 | 7167 | } |
| 7043 | 7168 | |
| 7044 | | const err_name, const error_payload = blk: { |
| 7045 | | const error_payload = main_tokens[catch_node] + 2; |
| 7169 | const err_name = blk: { |
| 7046 | 7170 | const err_str = tree.tokenSlice(error_payload); |
| 7047 | 7171 | if (mem.eql(u8, err_str, "_")) { |
| 7048 | 7172 | return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{}); |
| ... | ... | @@ -7050,7 +7174,7 @@ fn switchExprErrUnion( |
| 7050 | 7174 | const err_name = try astgen.identAsString(error_payload); |
| 7051 | 7175 | try astgen.detectLocalShadowing(scope, err_name, error_payload, err_str, .capture); |
| 7052 | 7176 | |
| 7053 | | break :blk .{ err_name, error_payload }; |
| 7177 | break :blk err_name; |
| 7054 | 7178 | }; |
| 7055 | 7179 | |
| 7056 | 7180 | // allocate a shared dummy instruction for the error capture |
| ... | ... | @@ -7241,6 +7365,7 @@ fn switchExprErrUnion( |
| 7241 | 7365 | .has_else = has_else, |
| 7242 | 7366 | .scalar_cases_len = @intCast(scalar_cases_len), |
| 7243 | 7367 | .any_uses_err_capture = any_uses_err_capture, |
| 7368 | .payload_is_ref = payload_is_ref, |
| 7244 | 7369 | }, |
| 7245 | 7370 | }); |
| 7246 | 7371 | |