| ... | @@ -839,7 +839,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -839,7 +839,18 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 839 | | 839 | |
| 840 | .if_simple, | 840 | .if_simple, |
| 841 | .@"if", | 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 | .while_simple, | 855 | .while_simple, |
| 845 | .while_cont, | 856 | .while_cont, |
| ... | @@ -1020,7 +1031,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE | ... | @@ -1020,7 +1031,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE |
| 1020 | token_tags[catch_token + 4] == .keyword_switch) | 1031 | token_tags[catch_token + 4] == .keyword_switch) |
| 1021 | { | 1032 | { |
| 1022 | if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) { | 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 | break :blk catch_token + 2; | 1037 | break :blk catch_token + 2; |
| ... | @@ -6869,7 +6880,8 @@ fn switchExprErrUnion( | ... | @@ -6869,7 +6880,8 @@ fn switchExprErrUnion( |
| 6869 | parent_gz: *GenZir, | 6880 | parent_gz: *GenZir, |
| 6870 | scope: *Scope, | 6881 | scope: *Scope, |
| 6871 | ri: ResultInfo, | 6882 | ri: ResultInfo, |
| 6872 | catch_node: Ast.Node.Index, | 6883 | catch_or_if_node: Ast.Node.Index, |
| | 6884 | node_ty: enum { @"catch", @"if" }, |
| 6873 | ) InnerError!Zir.Inst.Ref { | 6885 | ) InnerError!Zir.Inst.Ref { |
| 6874 | const astgen = parent_gz.astgen; | 6886 | const astgen = parent_gz.astgen; |
| 6875 | const gpa = astgen.gpa; | 6887 | const gpa = astgen.gpa; |
| ... | @@ -6878,21 +6890,42 @@ fn switchExprErrUnion( | ... | @@ -6878,21 +6890,42 @@ fn switchExprErrUnion( |
| 6878 | const node_tags = tree.nodes.items(.tag); | 6890 | const node_tags = tree.nodes.items(.tag); |
| 6879 | const main_tokens = tree.nodes.items(.main_token); | 6891 | const main_tokens = tree.nodes.items(.main_token); |
| 6880 | const token_tags = tree.tokens.items(.tag); | 6892 | const token_tags = tree.tokens.items(.tag); |
| 6881 | const operand_node = node_datas[catch_node].lhs; | 6893 | |
| 6882 | const switch_node = node_datas[catch_node].rhs; | 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 | const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); | 6913 | const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); |
| 6884 | const case_nodes = tree.extra_data[extra.start..extra.end]; | 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 | const block_ri: ResultInfo = if (need_rl) ri else .{ | 6917 | const block_ri: ResultInfo = if (need_rl) ri else .{ |
| 6888 | .rl = switch (ri.rl) { | 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 | .inferred_ptr => .none, | 6920 | .inferred_ptr => .none, |
| 6891 | else => ri.rl, | 6921 | else => ri.rl, |
| 6892 | }, | 6922 | }, |
| 6893 | .ctx = ri.ctx, | 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 | // We need to call `rvalue` to write through to the pointer only if we had a | 6929 | // We need to call `rvalue` to write through to the pointer only if we had a |
| 6897 | // result pointer and aren't forwarding it. | 6930 | // result pointer and aren't forwarding it. |
| 6898 | const LocTag = @typeInfo(ResultInfo.Loc).Union.tag_type.?; | 6931 | const LocTag = @typeInfo(ResultInfo.Loc).Union.tag_type.?; |
| ... | @@ -6960,12 +6993,15 @@ fn switchExprErrUnion( | ... | @@ -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 | astgen.advanceSourceCursorToNode(operand_node); | 7001 | astgen.advanceSourceCursorToNode(operand_node); |
| 6966 | const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column }; | 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 | const item_ri: ResultInfo = .{ .rl = .none }; | 7005 | const item_ri: ResultInfo = .{ .rl = .none }; |
| 6970 | | 7006 | |
| 6971 | // This contains the data that goes into the `extra` array for the SwitchBlockErrUnion, except | 7007 | // This contains the data that goes into the `extra` array for the SwitchBlockErrUnion, except |
| ... | @@ -7006,13 +7042,93 @@ fn switchExprErrUnion( | ... | @@ -7006,13 +7042,93 @@ fn switchExprErrUnion( |
| 7006 | | 7042 | |
| 7007 | try case_scope.addDbgBlockBegin(); | 7043 | try case_scope.addDbgBlockBegin(); |
| 7008 | | 7044 | |
| 7009 | const unwrapped_payload = try case_scope.addUnNode(.err_union_payload_unsafe, raw_operand, catch_node); | 7045 | const unwrap_payload_tag: Zir.Inst.Tag = if (payload_is_ref) |
| 7010 | const case_result = switch (ri.rl) { | 7046 | .err_union_payload_unsafe_ptr |
| 7011 | .ref, .ref_coerced_ty => unwrapped_payload, | 7047 | else |
| 7012 | else => try rvalue(&case_scope, block_scope.break_result_info, unwrapped_payload, catch_node), | 7048 | .err_union_payload_unsafe; |
| 7013 | }; | 7049 | |
| 7014 | try case_scope.addDbgBlockEnd(); | 7050 | const unwrapped_payload = try case_scope.addUnNode( |
| 7015 | _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, catch_node); | 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 | const case_slice = case_scope.instructionsSlice(); | 7133 | const case_slice = case_scope.instructionsSlice(); |
| 7018 | // Since we use the switch_block_err_union instruction itself to refer | 7134 | // Since we use the switch_block_err_union instruction itself to refer |
| ... | @@ -7029,9 +7145,18 @@ fn switchExprErrUnion( | ... | @@ -7029,9 +7145,18 @@ fn switchExprErrUnion( |
| 7029 | }; | 7145 | }; |
| 7030 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); | 7146 | const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice); |
| 7031 | try payloads.ensureUnusedCapacity(gpa, body_len); | 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 | payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{ | 7157 | payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{ |
| 7033 | .body_len = @intCast(body_len), | 7158 | .body_len = @intCast(body_len), |
| 7034 | .capture = .none, | 7159 | .capture = capture, |
| 7035 | .is_inline = false, | 7160 | .is_inline = false, |
| 7036 | .has_tag_capture = false, | 7161 | .has_tag_capture = false, |
| 7037 | }); | 7162 | }); |
| ... | @@ -7041,8 +7166,7 @@ fn switchExprErrUnion( | ... | @@ -7041,8 +7166,7 @@ fn switchExprErrUnion( |
| 7041 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); | 7166 | appendBodyWithFixupsArrayList(astgen, payloads, case_slice); |
| 7042 | } | 7167 | } |
| 7043 | | 7168 | |
| 7044 | const err_name, const error_payload = blk: { | 7169 | const err_name = blk: { |
| 7045 | const error_payload = main_tokens[catch_node] + 2; | | |
| 7046 | const err_str = tree.tokenSlice(error_payload); | 7170 | const err_str = tree.tokenSlice(error_payload); |
| 7047 | if (mem.eql(u8, err_str, "_")) { | 7171 | if (mem.eql(u8, err_str, "_")) { |
| 7048 | return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{}); | 7172 | return astgen.failTok(error_payload, "discard of error capture; omit it instead", .{}); |
| ... | @@ -7050,7 +7174,7 @@ fn switchExprErrUnion( | ... | @@ -7050,7 +7174,7 @@ fn switchExprErrUnion( |
| 7050 | const err_name = try astgen.identAsString(error_payload); | 7174 | const err_name = try astgen.identAsString(error_payload); |
| 7051 | try astgen.detectLocalShadowing(scope, err_name, error_payload, err_str, .capture); | 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 | // allocate a shared dummy instruction for the error capture | 7180 | // allocate a shared dummy instruction for the error capture |
| ... | @@ -7241,6 +7365,7 @@ fn switchExprErrUnion( | ... | @@ -7241,6 +7365,7 @@ fn switchExprErrUnion( |
| 7241 | .has_else = has_else, | 7365 | .has_else = has_else, |
| 7242 | .scalar_cases_len = @intCast(scalar_cases_len), | 7366 | .scalar_cases_len = @intCast(scalar_cases_len), |
| 7243 | .any_uses_err_capture = any_uses_err_capture, | 7367 | .any_uses_err_capture = any_uses_err_capture, |
| | 7368 | .payload_is_ref = payload_is_ref, |
| 7244 | }, | 7369 | }, |
| 7245 | }); | 7370 | }); |
| 7246 | | 7371 | |