Skip to content

Commit

Permalink
stage2: Propagate error return trace into fn call
Browse files Browse the repository at this point in the history
This change extends the "lifetime" of the error return trace associated
with an error to include the duration of a function call it is passed
to.

This means that if a function returns an error, its return trace will
include the error return trace for any error inputs. This is needed to
support `testing.expectError` and similar functions.

If a function returns a non-error, we have to clean up any error return
traces created by error-able call arguments.
  • Loading branch information
topolarity committed Sep 23, 2022
1 parent 0c04a45 commit 8427412
Show file tree
Hide file tree
Showing 3 changed files with 250 additions and 73 deletions.
17 changes: 9 additions & 8 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ pub const ResultInfo = struct {
/// such as if and switch expressions.
fn br(ri: ResultInfo) ResultInfo {
return switch (ri.rl) {
.coerced_ty => |ty| .{
.coerced_ty => |ty| .{
.rl = .{ .ty = ty },
.ctx = ri.ctx,
},
Expand All @@ -247,9 +247,11 @@ pub const ResultContext = enum {
/// The expression is the operand to a return expression.
@"return",
/// The expression is the input to an error-handling operator (if-else, try, or catch).
error_handling_expr,
error_handling_expr,
/// The expression is the right-hand side of a shift operation.
shift_op,
/// The expression is an argument in a function call.
fn_arg,
/// No specific operator in particular.
none,
};
Expand Down Expand Up @@ -1693,8 +1695,7 @@ fn structInitExprRlNone(
.container_type = ty_inst,
.name_start = str_index,
}) } }
else
.{ .rl = .none };
else .{ .rl = .none };
setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
.field_name = str_index,
.init = try expr(gz, scope, sub_ri, field_init),
Expand Down Expand Up @@ -5195,9 +5196,9 @@ fn popErrorReturnTrace(

const result_is_err = nodeMayEvalToError(tree, node);

// If we are breaking to a try/catch/error-union-if/return, the error trace propagates.
// If we are breaking to a try/catch/error-union-if/return or a function call, the error trace propagates.
const propagate_error_trace = switch (ri.ctx) {
.error_handling_expr, .@"return" => true,
.error_handling_expr, .@"return", .fn_arg => true,
else => false,
};

Expand Down Expand Up @@ -8462,7 +8463,7 @@ fn callExpr(
defer arg_block.unstack();

// `call_inst` is reused to provide the param type.
const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst } }, param_node);
const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node);
_ = try arg_block.addBreak(.break_inline, call_index, arg_ref);

const body = arg_block.instructionsSlice();
Expand All @@ -8476,7 +8477,7 @@ fn callExpr(
// If our result location is a try/catch/error-union-if/return, the error trace propagates.
// Otherwise, it should always be popped (handled in Sema).
const propagate_error_trace = switch (ri.ctx) {
.error_handling_expr, .@"return" => true, // Propagate to try/catch/error-union-if and return
.error_handling_expr, .@"return", .fn_arg => true, // Propagate to try/catch/error-union-if, return, and other function calls
else => false,
};

Expand Down
Loading

0 comments on commit 8427412

Please sign in to comment.