feature. See also
. The project being documented here (as the example) is the Zig library itself.
AstGen.tryExpr
fn tryExpr(
parent_gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
operand_node: Ast.Node.Index,
) InnerError!Zir.Inst.Ref
File
Code
fn tryExpr(
parent_gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
operand_node: Ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = parent_gz.astgen;
const fn_block = astgen.fn_block orelse {
return astgen.failNode(node, "'try' outside function scope", .{});
};
if (parent_gz.any_defer_node.unwrap()) |any_defer_node| {
return astgen.failNodeNotes(node, "'try' not allowed inside defer expression", .{}, &.{
try astgen.errNoteNode(
any_defer_node,
"defer expression here",
.{},
),
});
}
// Then we will save the line/column so that we can emit another one that goes
// "backwards" because we want to evaluate the operand, but then put the debug
// info back at the try keyword for error return tracing.
if (!parent_gz.is_comptime) {
try emitDbgNode(parent_gz, node);
}
const try_lc: LineColumn = .{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
const operand_rl: ResultInfo.Loc, const block_tag: Zir.Inst.Tag = switch (ri.rl) {
.ref, .ref_coerced_ty => .{ .ref, .try_ptr },
.ref_const => .{ .ref_const, .try_ptr },
else => .{ .none, .@"try" },
};
const operand_ri: ResultInfo = .{ .rl = operand_rl, .ctx = .error_handling_expr };
const operand = operand: {
// `try .foo(...)`
// This is a decl literal form, even though we don't propagate a result type through `try`.
var buf: [1]Ast.Node.Index = undefined;
if (astgen.tree.fullCall(&buf, operand_node)) |full_call| {
const res_ty: Zir.Inst.Ref = try ri.rl.resultType(parent_gz, operand_node) orelse .none;
break :operand try callExpr(parent_gz, scope, operand_ri, res_ty, operand_node, full_call);
}
break :operand try reachableExpr(parent_gz, scope, operand_ri, operand_node, node);
};
const try_inst = try parent_gz.makeBlockInst(block_tag, node);
try parent_gz.instructions.append(astgen.gpa, try_inst);
var else_scope = parent_gz.makeSubBlock(scope);
defer else_scope.unstack();
const err_tag = switch (ri.rl) {
.ref, .ref_const, .ref_coerced_ty => Zir.Inst.Tag.err_union_code_ptr,
else => Zir.Inst.Tag.err_union_code,
};
const err_code = try else_scope.addUnNode(err_tag, operand, node);
try genDefers(&else_scope, &fn_block.base, scope, .normal_and_error);
try emitDbgStmt(&else_scope, try_lc);
_ = try else_scope.addUnNode(.ret_node, err_code, node);
try else_scope.setTryBody(try_inst, operand);
const result = try_inst.toRef();
switch (ri.rl) {
.ref, .ref_const, .ref_coerced_ty => return result,
else => return rvalue(parent_gz, ri, result, node),
}
}