| ... | @@ -223,6 +223,10 @@ pub const ResultLoc = union(enum) { | ... | @@ -223,6 +223,10 @@ pub const ResultLoc = union(enum) { |
| 223 | /// The expression must generate a pointer rather than a value. For example, the left hand side | 223 | /// The expression must generate a pointer rather than a value. For example, the left hand side |
| 224 | /// of an assignment uses this kind of result location. | 224 | /// of an assignment uses this kind of result location. |
| 225 | ref, | 225 | ref, |
| | 226 | /// Exactly like `none`, except also indicates this is an error-handling expr (try/catch/return etc.) |
| | 227 | catch_none, |
| | 228 | /// Exactly like `ref`, except also indicates this is an error-handling expr (try/catch/return etc.) |
| | 229 | catch_ref, |
| 226 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. | 230 | /// The expression will be coerced into this type, but it will be evaluated as an rvalue. |
| 227 | ty: Zir.Inst.Ref, | 231 | ty: Zir.Inst.Ref, |
| 228 | /// Same as `ty` but for shift operands. | 232 | /// Same as `ty` but for shift operands. |
| ... | @@ -265,7 +269,7 @@ pub const ResultLoc = union(enum) { | ... | @@ -265,7 +269,7 @@ pub const ResultLoc = union(enum) { |
| 265 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { | 269 | fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy { |
| 266 | switch (rl) { | 270 | switch (rl) { |
| 267 | // In this branch there will not be any store_to_block_ptr instructions. | 271 | // In this branch there will not be any store_to_block_ptr instructions. |
| 268 | .none, .ty, .ty_shift_operand, .coerced_ty, .ref => return .{ | 272 | .none, .catch_none, .ty, .ty_shift_operand, .coerced_ty, .ref, .catch_ref => return .{ |
| 269 | .tag = .break_operand, | 273 | .tag = .break_operand, |
| 270 | .elide_store_to_block_ptr_instructions = false, | 274 | .elide_store_to_block_ptr_instructions = false, |
| 271 | }, | 275 | }, |
| ... | @@ -838,7 +842,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr | ... | @@ -838,7 +842,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 838 | const lhs = try expr(gz, scope, .none, node_datas[node].lhs); | 842 | const lhs = try expr(gz, scope, .none, node_datas[node].lhs); |
| 839 | _ = try gz.addUnNode(.validate_deref, lhs, node); | 843 | _ = try gz.addUnNode(.validate_deref, lhs, node); |
| 840 | switch (rl) { | 844 | switch (rl) { |
| 841 | .ref => return lhs, | 845 | .ref, .catch_ref => return lhs, |
| 842 | else => { | 846 | else => { |
| 843 | const result = try gz.addUnNode(.load, lhs, node); | 847 | const result = try gz.addUnNode(.load, lhs, node); |
| 844 | return rvalue(gz, rl, result, node); | 848 | return rvalue(gz, rl, result, node); |
| ... | @@ -855,7 +859,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr | ... | @@ -855,7 +859,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 855 | return rvalue(gz, rl, result, node); | 859 | return rvalue(gz, rl, result, node); |
| 856 | }, | 860 | }, |
| 857 | .unwrap_optional => switch (rl) { | 861 | .unwrap_optional => switch (rl) { |
| 858 | .ref => return gz.addUnNode( | 862 | .ref, .catch_ref => return gz.addUnNode( |
| 859 | .optional_payload_safe_ptr, | 863 | .optional_payload_safe_ptr, |
| 860 | try expr(gz, scope, .ref, node_datas[node].lhs), | 864 | try expr(gz, scope, .ref, node_datas[node].lhs), |
| 861 | node, | 865 | node, |
| ... | @@ -900,7 +904,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr | ... | @@ -900,7 +904,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 900 | else | 904 | else |
| 901 | null; | 905 | null; |
| 902 | switch (rl) { | 906 | switch (rl) { |
| 903 | .ref => return orelseCatchExpr( | 907 | .ref, .catch_ref => return orelseCatchExpr( |
| 904 | gz, | 908 | gz, |
| 905 | scope, | 909 | scope, |
| 906 | rl, | 910 | rl, |
| ... | @@ -927,7 +931,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr | ... | @@ -927,7 +931,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 927 | } | 931 | } |
| 928 | }, | 932 | }, |
| 929 | .@"orelse" => switch (rl) { | 933 | .@"orelse" => switch (rl) { |
| 930 | .ref => return orelseCatchExpr( | 934 | .ref, .catch_ref => return orelseCatchExpr( |
| 931 | gz, | 935 | gz, |
| 932 | scope, | 936 | scope, |
| 933 | rl, | 937 | rl, |
| ... | @@ -1372,11 +1376,11 @@ fn arrayInitExpr( | ... | @@ -1372,11 +1376,11 @@ fn arrayInitExpr( |
| 1372 | } | 1376 | } |
| 1373 | return Zir.Inst.Ref.void_value; | 1377 | return Zir.Inst.Ref.void_value; |
| 1374 | }, | 1378 | }, |
| 1375 | .ref => { | 1379 | .ref, .catch_ref => { |
| 1376 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref; | 1380 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref; |
| 1377 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); | 1381 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); |
| 1378 | }, | 1382 | }, |
| 1379 | .none => { | 1383 | .none, .catch_none => { |
| 1380 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; | 1384 | const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon; |
| 1381 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); | 1385 | return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag); |
| 1382 | }, | 1386 | }, |
| ... | @@ -1608,7 +1612,7 @@ fn structInitExpr( | ... | @@ -1608,7 +1612,7 @@ fn structInitExpr( |
| 1608 | } | 1612 | } |
| 1609 | return Zir.Inst.Ref.void_value; | 1613 | return Zir.Inst.Ref.void_value; |
| 1610 | }, | 1614 | }, |
| 1611 | .ref => { | 1615 | .ref, .catch_ref => { |
| 1612 | if (struct_init.ast.type_expr != 0) { | 1616 | if (struct_init.ast.type_expr != 0) { |
| 1613 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 1617 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1614 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | 1618 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| ... | @@ -1617,7 +1621,7 @@ fn structInitExpr( | ... | @@ -1617,7 +1621,7 @@ fn structInitExpr( |
| 1617 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); | 1621 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); |
| 1618 | } | 1622 | } |
| 1619 | }, | 1623 | }, |
| 1620 | .none => { | 1624 | .none, .catch_none => { |
| 1621 | if (struct_init.ast.type_expr != 0) { | 1625 | if (struct_init.ast.type_expr != 0) { |
| 1622 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 1626 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1623 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | 1627 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| ... | @@ -1891,15 +1895,8 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn | ... | @@ -1891,15 +1895,8 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn |
| 1891 | | 1895 | |
| 1892 | // As our last action before the break, "pop" the error trace if needed | 1896 | // As our last action before the break, "pop" the error trace if needed |
| 1893 | if (err_trace_index_to_restore != .none) { | 1897 | if (err_trace_index_to_restore != .none) { |
| 1894 | // TODO: error-liveness and is_non_err | 1898 | // void is a non-error so we always pop - no need to call `popErrorReturnTrace` |
| 1895 | | 1899 | _ = try parent_gz.addUnNode(.restore_err_ret_index, err_trace_index_to_restore, node); |
| 1896 | _ = try parent_gz.add(.{ | | |
| 1897 | .tag = .restore_err_ret_index, | | |
| 1898 | .data = .{ .un_node = .{ | | |
| 1899 | .operand = err_trace_index_to_restore, | | |
| 1900 | .src_node = parent_gz.nodeIndexToRelative(node), | | |
| 1901 | } }, | | |
| 1902 | }); | | |
| 1903 | } | 1900 | } |
| 1904 | | 1901 | |
| 1905 | _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); | 1902 | _ = try parent_gz.addBreak(break_tag, block_inst, .void_value); |
| ... | @@ -1914,15 +1911,15 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn | ... | @@ -1914,15 +1911,15 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn |
| 1914 | | 1911 | |
| 1915 | // As our last action before the break, "pop" the error trace if needed | 1912 | // As our last action before the break, "pop" the error trace if needed |
| 1916 | if (err_trace_index_to_restore != .none) { | 1913 | if (err_trace_index_to_restore != .none) { |
| 1917 | // TODO: error-liveness and is_non_err | 1914 | // Pop the error trace, unless the operand is an error and breaking to an error-handling expr. |
| 1918 | | 1915 | try popErrorReturnTrace( |
| 1919 | _ = try parent_gz.add(.{ | 1916 | parent_gz, |
| 1920 | .tag = .restore_err_ret_index, | 1917 | scope, |
| 1921 | .data = .{ .un_node = .{ | 1918 | block_gz.break_result_loc, |
| 1922 | .operand = err_trace_index_to_restore, | 1919 | rhs, |
| 1923 | .src_node = parent_gz.nodeIndexToRelative(node), | 1920 | operand, |
| 1924 | } }, | 1921 | err_trace_index_to_restore, |
| 1925 | }); | 1922 | ); |
| 1926 | } | 1923 | } |
| 1927 | | 1924 | |
| 1928 | switch (block_gz.break_result_loc) { | 1925 | switch (block_gz.break_result_loc) { |
| ... | @@ -2177,7 +2174,7 @@ fn labeledBlockExpr( | ... | @@ -2177,7 +2174,7 @@ fn labeledBlockExpr( |
| 2177 | try block_scope.setBlockBody(block_inst); | 2174 | try block_scope.setBlockBody(block_inst); |
| 2178 | const block_ref = indexToRef(block_inst); | 2175 | const block_ref = indexToRef(block_inst); |
| 2179 | switch (rl) { | 2176 | switch (rl) { |
| 2180 | .ref => return block_ref, | 2177 | .ref, .catch_ref => return block_ref, |
| 2181 | else => return rvalue(gz, rl, block_ref, block_node), | 2178 | else => return rvalue(gz, rl, block_ref, block_node), |
| 2182 | } | 2179 | } |
| 2183 | }, | 2180 | }, |
| ... | @@ -5141,14 +5138,14 @@ fn tryExpr( | ... | @@ -5141,14 +5138,14 @@ fn tryExpr( |
| 5141 | const try_column = astgen.source_column; | 5138 | const try_column = astgen.source_column; |
| 5142 | | 5139 | |
| 5143 | const operand_rl: ResultLoc = switch (rl) { | 5140 | const operand_rl: ResultLoc = switch (rl) { |
| 5144 | .ref => .ref, | 5141 | .ref, .catch_ref => .catch_ref, |
| 5145 | else => .none, | 5142 | else => .catch_none, |
| 5146 | }; | 5143 | }; |
| 5147 | // This could be a pointer or value depending on the `rl` parameter. | 5144 | // This could be a pointer or value depending on the `rl` parameter. |
| 5148 | const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node); | 5145 | const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node); |
| 5149 | const is_inline = parent_gz.force_comptime; | 5146 | const is_inline = parent_gz.force_comptime; |
| 5150 | const is_inline_bit = @as(u2, @boolToInt(is_inline)); | 5147 | const is_inline_bit = @as(u2, @boolToInt(is_inline)); |
| 5151 | const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1; | 5148 | const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref or operand_rl == .catch_ref)) << 1; |
| 5152 | const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) { | 5149 | const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) { |
| 5153 | 0b00 => .@"try", | 5150 | 0b00 => .@"try", |
| 5154 | 0b01 => .@"try", | 5151 | 0b01 => .@"try", |
| ... | @@ -5164,7 +5161,7 @@ fn tryExpr( | ... | @@ -5164,7 +5161,7 @@ fn tryExpr( |
| 5164 | defer else_scope.unstack(); | 5161 | defer else_scope.unstack(); |
| 5165 | | 5162 | |
| 5166 | const err_tag = switch (rl) { | 5163 | const err_tag = switch (rl) { |
| 5167 | .ref => Zir.Inst.Tag.err_union_code_ptr, | 5164 | .ref, .catch_ref => Zir.Inst.Tag.err_union_code_ptr, |
| 5168 | else => Zir.Inst.Tag.err_union_code, | 5165 | else => Zir.Inst.Tag.err_union_code, |
| 5169 | }; | 5166 | }; |
| 5170 | const err_code = try else_scope.addUnNode(err_tag, operand, node); | 5167 | const err_code = try else_scope.addUnNode(err_tag, operand, node); |
| ... | @@ -5175,11 +5172,86 @@ fn tryExpr( | ... | @@ -5175,11 +5172,86 @@ fn tryExpr( |
| 5175 | try else_scope.setTryBody(try_inst, operand); | 5172 | try else_scope.setTryBody(try_inst, operand); |
| 5176 | const result = indexToRef(try_inst); | 5173 | const result = indexToRef(try_inst); |
| 5177 | switch (rl) { | 5174 | switch (rl) { |
| 5178 | .ref => return result, | 5175 | .ref, .catch_ref => return result, |
| 5179 | else => return rvalue(parent_gz, rl, result, node), | 5176 | else => return rvalue(parent_gz, rl, result, node), |
| 5180 | } | 5177 | } |
| 5181 | } | 5178 | } |
| 5182 | | 5179 | |
| | 5180 | /// Pops the error return trace, unless: |
| | 5181 | /// 1. the result is a non-error, AND |
| | 5182 | /// 2. the result location corresponds to an error-handling expression |
| | 5183 | /// |
| | 5184 | /// For reference, the full list of error-handling expressions is: |
| | 5185 | /// - try X |
| | 5186 | /// - X catch ... |
| | 5187 | /// - if (X) |_| { ... } |_| { ... } |
| | 5188 | /// - return X |
| | 5189 | /// |
| | 5190 | fn popErrorReturnTrace( |
| | 5191 | gz: *GenZir, |
| | 5192 | scope: *Scope, |
| | 5193 | rl: ResultLoc, |
| | 5194 | node: Ast.Node.Index, |
| | 5195 | result_inst: Zir.Inst.Ref, |
| | 5196 | error_trace_index: Zir.Inst.Ref, |
| | 5197 | ) InnerError!void { |
| | 5198 | const astgen = gz.astgen; |
| | 5199 | const tree = astgen.tree; |
| | 5200 | |
| | 5201 | const result_is_err = nodeMayEvalToError(tree, node); |
| | 5202 | |
| | 5203 | // If we are breaking to a try/catch/error-union-if/return, the error trace propagates. |
| | 5204 | const propagate_error_trace = switch (rl) { |
| | 5205 | .catch_none, .catch_ref => true, // Propagate to try/catch/error-union-if |
| | 5206 | .ptr, .ty => |ref| b: { // Otherwise, propagate if result loc is a return |
| | 5207 | const inst = refToIndex(ref) orelse break :b false; |
| | 5208 | const zir_tags = astgen.instructions.items(.tag); |
| | 5209 | break :b zir_tags[inst] == .ret_ptr or zir_tags[inst] == .ret_type; |
| | 5210 | }, |
| | 5211 | else => false, |
| | 5212 | }; |
| | 5213 | |
| | 5214 | if (result_is_err == .never or !propagate_error_trace) { |
| | 5215 | // We are returning a non-error, or returning to a non-error-handling operator. |
| | 5216 | // In either case, we need to pop the error trace. |
| | 5217 | _ = try gz.addUnNode(.restore_err_ret_index, error_trace_index, node); |
| | 5218 | } else if (result_is_err == .maybe) { |
| | 5219 | // We are returning to an error-handling operator with a maybe-error. |
| | 5220 | // Restore only if it's a non-error, implying the catch was successfully handled. |
| | 5221 | var block_scope = gz.makeSubBlock(scope); |
| | 5222 | block_scope.setBreakResultLoc(.discard); |
| | 5223 | defer block_scope.unstack(); |
| | 5224 | |
| | 5225 | // Emit conditional branch for restoring error trace index |
| | 5226 | const is_non_err = switch (rl) { |
| | 5227 | .catch_ref => try block_scope.addUnNode(.is_non_err_ptr, result_inst, node), |
| | 5228 | .ptr => |ptr| try block_scope.addUnNode(.is_non_err_ptr, ptr, node), |
| | 5229 | .ty, .catch_none => try block_scope.addUnNode(.is_non_err, result_inst, node), |
| | 5230 | else => unreachable, // Error-handling operators only generate the above result locations |
| | 5231 | }; |
| | 5232 | const condbr = try block_scope.addCondBr(.condbr, node); |
| | 5233 | |
| | 5234 | const block = try gz.makeBlockInst(.block, node); |
| | 5235 | try block_scope.setBlockBody(block); |
| | 5236 | // block_scope unstacked now, can add new instructions to gz |
| | 5237 | |
| | 5238 | try gz.instructions.append(astgen.gpa, block); |
| | 5239 | |
| | 5240 | var then_scope = block_scope.makeSubBlock(scope); |
| | 5241 | defer then_scope.unstack(); |
| | 5242 | |
| | 5243 | _ = try then_scope.addUnNode(.restore_err_ret_index, error_trace_index, node); |
| | 5244 | const then_break = try then_scope.makeBreak(.@"break", block, .void_value); |
| | 5245 | |
| | 5246 | var else_scope = block_scope.makeSubBlock(scope); |
| | 5247 | defer else_scope.unstack(); |
| | 5248 | |
| | 5249 | const else_break = try else_scope.makeBreak(.@"break", block, .void_value); |
| | 5250 | |
| | 5251 | try setCondBrPayload(condbr, is_non_err, &then_scope, then_break, &else_scope, else_break); |
| | 5252 | } |
| | 5253 | } |
| | 5254 | |
| 5183 | fn orelseCatchExpr( | 5255 | fn orelseCatchExpr( |
| 5184 | parent_gz: *GenZir, | 5256 | parent_gz: *GenZir, |
| 5185 | scope: *Scope, | 5257 | scope: *Scope, |
| ... | @@ -5204,8 +5276,8 @@ fn orelseCatchExpr( | ... | @@ -5204,8 +5276,8 @@ fn orelseCatchExpr( |
| 5204 | const saved_err_trace_index = if (do_err_trace) try parent_gz.addNode(.save_err_ret_index, node) else .none; | 5276 | const saved_err_trace_index = if (do_err_trace) try parent_gz.addNode(.save_err_ret_index, node) else .none; |
| 5205 | | 5277 | |
| 5206 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { | 5278 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 5207 | .ref => .ref, | 5279 | .ref, .catch_ref => if (do_err_trace) ResultLoc{ .catch_ref = {} } else .ref, |
| 5208 | else => .none, | 5280 | else => if (do_err_trace) ResultLoc{ .catch_none = {} } else .none, |
| 5209 | }; | 5281 | }; |
| 5210 | block_scope.break_count += 1; | 5282 | block_scope.break_count += 1; |
| 5211 | // This could be a pointer or value depending on the `operand_rl` parameter. | 5283 | // This could be a pointer or value depending on the `operand_rl` parameter. |
| ... | @@ -5227,7 +5299,7 @@ fn orelseCatchExpr( | ... | @@ -5227,7 +5299,7 @@ fn orelseCatchExpr( |
| 5227 | // This could be a pointer or value depending on `unwrap_op`. | 5299 | // This could be a pointer or value depending on `unwrap_op`. |
| 5228 | const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); | 5300 | const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); |
| 5229 | const then_result = switch (rl) { | 5301 | const then_result = switch (rl) { |
| 5230 | .ref => unwrapped_payload, | 5302 | .ref, .catch_ref => unwrapped_payload, |
| 5231 | else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), | 5303 | else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), |
| 5232 | }; | 5304 | }; |
| 5233 | | 5305 | |
| ... | @@ -5266,15 +5338,15 @@ fn orelseCatchExpr( | ... | @@ -5266,15 +5338,15 @@ fn orelseCatchExpr( |
| 5266 | if (!else_scope.endsWithNoReturn()) { | 5338 | if (!else_scope.endsWithNoReturn()) { |
| 5267 | block_scope.break_count += 1; | 5339 | block_scope.break_count += 1; |
| 5268 | | 5340 | |
| 5269 | // TODO: Add is_non_err and break check | | |
| 5270 | if (do_err_trace) { | 5341 | if (do_err_trace) { |
| 5271 | _ = try else_scope.add(.{ | 5342 | try popErrorReturnTrace( |
| 5272 | .tag = .restore_err_ret_index, | 5343 | &else_scope, |
| 5273 | .data = .{ .un_node = .{ | 5344 | else_sub_scope, |
| 5274 | .operand = saved_err_trace_index, | 5345 | block_scope.break_result_loc, |
| 5275 | .src_node = parent_gz.nodeIndexToRelative(node), | 5346 | rhs, |
| 5276 | } }, | 5347 | else_result, |
| 5277 | }); | 5348 | saved_err_trace_index, |
| | 5349 | ); |
| 5278 | } | 5350 | } |
| 5279 | } | 5351 | } |
| 5280 | try checkUsed(parent_gz, &else_scope.base, else_sub_scope); | 5352 | try checkUsed(parent_gz, &else_scope.base, else_sub_scope); |
| ... | @@ -5351,7 +5423,7 @@ fn finishThenElseBlock( | ... | @@ -5351,7 +5423,7 @@ fn finishThenElseBlock( |
| 5351 | } | 5423 | } |
| 5352 | const block_ref = indexToRef(main_block); | 5424 | const block_ref = indexToRef(main_block); |
| 5353 | switch (rl) { | 5425 | switch (rl) { |
| 5354 | .ref => return block_ref, | 5426 | .ref, .catch_ref => return block_ref, |
| 5355 | else => return rvalue(parent_gz, rl, block_ref, node), | 5427 | else => return rvalue(parent_gz, rl, block_ref, node), |
| 5356 | } | 5428 | } |
| 5357 | }, | 5429 | }, |
| ... | @@ -5375,7 +5447,7 @@ fn fieldAccess( | ... | @@ -5375,7 +5447,7 @@ fn fieldAccess( |
| 5375 | node: Ast.Node.Index, | 5447 | node: Ast.Node.Index, |
| 5376 | ) InnerError!Zir.Inst.Ref { | 5448 | ) InnerError!Zir.Inst.Ref { |
| 5377 | switch (rl) { | 5449 | switch (rl) { |
| 5378 | .ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node), | 5450 | .ref, .catch_ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node), |
| 5379 | else => { | 5451 | else => { |
| 5380 | const access = try addFieldAccess(.field_val, gz, scope, .none, node); | 5452 | const access = try addFieldAccess(.field_val, gz, scope, .none, node); |
| 5381 | return rvalue(gz, rl, access, node); | 5453 | return rvalue(gz, rl, access, node); |
| ... | @@ -5416,7 +5488,7 @@ fn arrayAccess( | ... | @@ -5416,7 +5488,7 @@ fn arrayAccess( |
| 5416 | const tree = astgen.tree; | 5488 | const tree = astgen.tree; |
| 5417 | const node_datas = tree.nodes.items(.data); | 5489 | const node_datas = tree.nodes.items(.data); |
| 5418 | switch (rl) { | 5490 | switch (rl) { |
| 5419 | .ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ | 5491 | .ref, .catch_ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ |
| 5420 | .lhs = try expr(gz, scope, .ref, node_datas[node].lhs), | 5492 | .lhs = try expr(gz, scope, .ref, node_datas[node].lhs), |
| 5421 | .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), | 5493 | .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs), |
| 5422 | }), | 5494 | }), |
| ... | @@ -5514,7 +5586,7 @@ fn ifExpr( | ... | @@ -5514,7 +5586,7 @@ fn ifExpr( |
| 5514 | bool_bit: Zir.Inst.Ref, | 5586 | bool_bit: Zir.Inst.Ref, |
| 5515 | } = c: { | 5587 | } = c: { |
| 5516 | if (if_full.error_token) |_| { | 5588 | if (if_full.error_token) |_| { |
| 5517 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; | 5589 | const cond_rl: ResultLoc = if (payload_is_ref) .catch_ref else .catch_none; |
| 5518 | const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); | 5590 | const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr); |
| 5519 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; | 5591 | const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err; |
| 5520 | break :c .{ | 5592 | break :c .{ |
| ... | @@ -5660,6 +5732,17 @@ fn ifExpr( | ... | @@ -5660,6 +5732,17 @@ fn ifExpr( |
| 5660 | const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); | 5732 | const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node); |
| 5661 | if (!else_scope.endsWithNoReturn()) { | 5733 | if (!else_scope.endsWithNoReturn()) { |
| 5662 | block_scope.break_count += 1; | 5734 | block_scope.break_count += 1; |
| | 5735 | |
| | 5736 | if (do_err_trace) { |
| | 5737 | try popErrorReturnTrace( |
| | 5738 | &else_scope, |
| | 5739 | sub_scope, |
| | 5740 | block_scope.break_result_loc, |
| | 5741 | else_node, |
| | 5742 | e, |
| | 5743 | saved_err_trace_index, |
| | 5744 | ); |
| | 5745 | } |
| 5663 | } | 5746 | } |
| 5664 | try checkUsed(parent_gz, &else_scope.base, sub_scope); | 5747 | try checkUsed(parent_gz, &else_scope.base, sub_scope); |
| 5665 | try else_scope.addDbgBlockEnd(); | 5748 | try else_scope.addDbgBlockEnd(); |
| ... | @@ -5676,18 +5759,6 @@ fn ifExpr( | ... | @@ -5676,18 +5759,6 @@ fn ifExpr( |
| 5676 | }, | 5759 | }, |
| 5677 | }; | 5760 | }; |
| 5678 | | 5761 | |
| 5679 | if (do_err_trace and !else_scope.endsWithNoReturn()) { | | |
| 5680 | // TODO: is_non_err and other checks | | |
| 5681 | | | |
| 5682 | _ = try else_scope.add(.{ | | |
| 5683 | .tag = .restore_err_ret_index, | | |
| 5684 | .data = .{ .un_node = .{ | | |
| 5685 | .operand = saved_err_trace_index, | | |
| 5686 | .src_node = parent_gz.nodeIndexToRelative(node), | | |
| 5687 | } }, | | |
| 5688 | }); | | |
| 5689 | } | | |
| 5690 | | | |
| 5691 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; | 5762 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; |
| 5692 | const result = try finishThenElseBlock( | 5763 | const result = try finishThenElseBlock( |
| 5693 | parent_gz, | 5764 | parent_gz, |
| ... | @@ -6760,7 +6831,7 @@ fn switchExpr( | ... | @@ -6760,7 +6831,7 @@ fn switchExpr( |
| 6760 | } | 6831 | } |
| 6761 | | 6832 | |
| 6762 | const block_ref = indexToRef(switch_block); | 6833 | const block_ref = indexToRef(switch_block); |
| 6763 | if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref) | 6834 | if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref and rl != .catch_ref) |
| 6764 | return rvalue(parent_gz, rl, block_ref, switch_node); | 6835 | return rvalue(parent_gz, rl, block_ref, switch_node); |
| 6765 | return block_ref; | 6836 | return block_ref; |
| 6766 | } | 6837 | } |
| ... | @@ -6839,19 +6910,12 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6839,19 +6910,12 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6839 | .never => { | 6910 | .never => { |
| 6840 | // Returning a value that cannot be an error; skip error defers. | 6911 | // Returning a value that cannot be an error; skip error defers. |
| 6841 | try genDefers(gz, defer_outer, scope, .normal_only); | 6912 | try genDefers(gz, defer_outer, scope, .normal_only); |
| 6842 | try emitDbgStmt(gz, ret_line, ret_column); | | |
| 6843 | | 6913 | |
| 6844 | // As our last action before the return, "pop" the error trace if needed | 6914 | // As our last action before the return, "pop" the error trace if needed |
| 6845 | if (gz.outermost_err_trace_index != .none) { | 6915 | if (gz.outermost_err_trace_index != .none) |
| 6846 | _ = try gz.add(.{ | 6916 | _ = try gz.addUnNode(.restore_err_ret_index, gz.outermost_err_trace_index, node); |
| 6847 | .tag = .restore_err_ret_index, | | |
| 6848 | .data = .{ .un_node = .{ | | |
| 6849 | .operand = gz.outermost_err_trace_index, | | |
| 6850 | .src_node = gz.nodeIndexToRelative(node), | | |
| 6851 | } }, | | |
| 6852 | }); | | |
| 6853 | } | | |
| 6854 | | 6917 | |
| | 6918 | try emitDbgStmt(gz, ret_line, ret_column); |
| 6855 | try gz.addRet(rl, operand, node); | 6919 | try gz.addRet(rl, operand, node); |
| 6856 | return Zir.Inst.Ref.unreachable_value; | 6920 | return Zir.Inst.Ref.unreachable_value; |
| 6857 | }, | 6921 | }, |
| ... | @@ -6882,6 +6946,11 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6882,6 +6946,11 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6882 | defer then_scope.unstack(); | 6946 | defer then_scope.unstack(); |
| 6883 | | 6947 | |
| 6884 | try genDefers(&then_scope, defer_outer, scope, .normal_only); | 6948 | try genDefers(&then_scope, defer_outer, scope, .normal_only); |
| | 6949 | |
| | 6950 | // As our last action before the return, "pop" the error trace if needed |
| | 6951 | if (then_scope.outermost_err_trace_index != .none) |
| | 6952 | _ = try then_scope.addUnNode(.restore_err_ret_index, then_scope.outermost_err_trace_index, node); |
| | 6953 | |
| 6885 | try emitDbgStmt(&then_scope, ret_line, ret_column); | 6954 | try emitDbgStmt(&then_scope, ret_line, ret_column); |
| 6886 | try then_scope.addRet(rl, operand, node); | 6955 | try then_scope.addRet(rl, operand, node); |
| 6887 | | 6956 | |
| ... | @@ -6893,17 +6962,6 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref | ... | @@ -6893,17 +6962,6 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 6893 | }; | 6962 | }; |
| 6894 | try genDefers(&else_scope, defer_outer, scope, which_ones); | 6963 | try genDefers(&else_scope, defer_outer, scope, which_ones); |
| 6895 | try emitDbgStmt(&else_scope, ret_line, ret_column); | 6964 | try emitDbgStmt(&else_scope, ret_line, ret_column); |
| 6896 | | | |
| 6897 | // As our last action before the return, "pop" the error trace if needed | | |
| 6898 | if (else_scope.outermost_err_trace_index != .none) { | | |
| 6899 | _ = try else_scope.add(.{ | | |
| 6900 | .tag = .restore_err_ret_index, | | |
| 6901 | .data = .{ .un_node = .{ | | |
| 6902 | .operand = else_scope.outermost_err_trace_index, | | |
| 6903 | .src_node = else_scope.nodeIndexToRelative(node), | | |
| 6904 | } }, | | |
| 6905 | }); | | |
| 6906 | } | | |
| 6907 | try else_scope.addRet(rl, operand, node); | 6965 | try else_scope.addRet(rl, operand, node); |
| 6908 | | 6966 | |
| 6909 | try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); | 6967 | try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); |
| ... | @@ -7068,7 +7126,7 @@ fn localVarRef( | ... | @@ -7068,7 +7126,7 @@ fn localVarRef( |
| 7068 | ); | 7126 | ); |
| 7069 | | 7127 | |
| 7070 | switch (rl) { | 7128 | switch (rl) { |
| 7071 | .ref => return ptr_inst, | 7129 | .ref, .catch_ref => return ptr_inst, |
| 7072 | else => { | 7130 | else => { |
| 7073 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); | 7131 | const loaded = try gz.addUnNode(.load, ptr_inst, ident); |
| 7074 | return rvalue(gz, rl, loaded, ident); | 7132 | return rvalue(gz, rl, loaded, ident); |
| ... | @@ -7105,7 +7163,7 @@ fn localVarRef( | ... | @@ -7105,7 +7163,7 @@ fn localVarRef( |
| 7105 | // Decl references happen by name rather than ZIR index so that when unrelated | 7163 | // Decl references happen by name rather than ZIR index so that when unrelated |
| 7106 | // decls are modified, ZIR code containing references to them can be unmodified. | 7164 | // decls are modified, ZIR code containing references to them can be unmodified. |
| 7107 | switch (rl) { | 7165 | switch (rl) { |
| 7108 | .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | 7166 | .ref, .catch_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token), |
| 7109 | else => { | 7167 | else => { |
| 7110 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); | 7168 | const result = try gz.addStrTok(.decl_val, name_str_index, ident_token); |
| 7111 | return rvalue(gz, rl, result, ident); | 7169 | return rvalue(gz, rl, result, ident); |
| ... | @@ -7452,7 +7510,7 @@ fn as( | ... | @@ -7452,7 +7510,7 @@ fn as( |
| 7452 | ) InnerError!Zir.Inst.Ref { | 7510 | ) InnerError!Zir.Inst.Ref { |
| 7453 | const dest_type = try typeExpr(gz, scope, lhs); | 7511 | const dest_type = try typeExpr(gz, scope, lhs); |
| 7454 | switch (rl) { | 7512 | switch (rl) { |
| 7455 | .none, .discard, .ref, .ty, .ty_shift_operand, .coerced_ty => { | 7513 | .none, .catch_none, .discard, .ref, .catch_ref, .ty, .ty_shift_operand, .coerced_ty => { |
| 7456 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); | 7514 | const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node); |
| 7457 | return rvalue(gz, rl, result, node); | 7515 | return rvalue(gz, rl, result, node); |
| 7458 | }, | 7516 | }, |
| ... | @@ -7652,7 +7710,7 @@ fn builtinCall( | ... | @@ -7652,7 +7710,7 @@ fn builtinCall( |
| 7652 | return rvalue(gz, rl, result, node); | 7710 | return rvalue(gz, rl, result, node); |
| 7653 | }, | 7711 | }, |
| 7654 | .field => { | 7712 | .field => { |
| 7655 | if (rl == .ref) { | 7713 | if (rl == .ref or rl == .catch_ref) { |
| 7656 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ | 7714 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ |
| 7657 | .lhs = try expr(gz, scope, .ref, params[0]), | 7715 | .lhs = try expr(gz, scope, .ref, params[0]), |
| 7658 | .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), | 7716 | .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]), |
| ... | @@ -9600,13 +9658,13 @@ fn rvalue( | ... | @@ -9600,13 +9658,13 @@ fn rvalue( |
| 9600 | }; | 9658 | }; |
| 9601 | if (gz.endsWithNoReturn()) return result; | 9659 | if (gz.endsWithNoReturn()) return result; |
| 9602 | switch (rl) { | 9660 | switch (rl) { |
| 9603 | .none, .coerced_ty => return result, | 9661 | .none, .catch_none, .coerced_ty => return result, |
| 9604 | .discard => { | 9662 | .discard => { |
| 9605 | // Emit a compile error for discarding error values. | 9663 | // Emit a compile error for discarding error values. |
| 9606 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); | 9664 | _ = try gz.addUnNode(.ensure_result_non_error, result, src_node); |
| 9607 | return result; | 9665 | return result; |
| 9608 | }, | 9666 | }, |
| 9609 | .ref => { | 9667 | .ref, .catch_ref => { |
| 9610 | // We need a pointer but we have a value. | 9668 | // We need a pointer but we have a value. |
| 9611 | // Unfortunately it's not quite as simple as directly emitting a ref | 9669 | // Unfortunately it's not quite as simple as directly emitting a ref |
| 9612 | // instruction here because we need subsequent address-of operator on | 9670 | // instruction here because we need subsequent address-of operator on |
| ... | @@ -10575,7 +10633,7 @@ const GenZir = struct { | ... | @@ -10575,7 +10633,7 @@ const GenZir = struct { |
| 10575 | gz.break_result_loc = parent_rl; | 10633 | gz.break_result_loc = parent_rl; |
| 10576 | }, | 10634 | }, |
| 10577 | | 10635 | |
| 10578 | .discard, .none, .ref => { | 10636 | .discard, .none, .catch_none, .ref, .catch_ref => { |
| 10579 | gz.rl_ty_inst = .none; | 10637 | gz.rl_ty_inst = .none; |
| 10580 | gz.break_result_loc = parent_rl; | 10638 | gz.break_result_loc = parent_rl; |
| 10581 | }, | 10639 | }, |