DoxigAlpha

labeledBlockExpr

Function parameters

Parameters

#
gz:*GenZir
parent_scope:*Scope
block_node:Ast.Node.Index
statements:[]const Ast.Node.Index
force_comptime:bool

Functions in this namespace

Functions

#

Source

Implementation

#
fn labeledBlockExpr(
    gz: *GenZir,
    parent_scope: *Scope,
    ri: ResultInfo,
    block_node: Ast.Node.Index,
    statements: []const Ast.Node.Index,
    force_comptime: bool,
    block_kind: BlockKind,
) InnerError!Zir.Inst.Ref {
    const astgen = gz.astgen;
    const tree = astgen.tree;

    const lbrace = tree.nodeMainToken(block_node);
    const label_token = lbrace - 2;
    assert(tree.tokenTag(label_token) == .identifier);

    try astgen.checkLabelRedefinition(parent_scope, label_token);

    const need_rl = astgen.nodes_need_rl.contains(block_node);
    const block_ri: ResultInfo = if (need_rl) ri else .{
        .rl = switch (ri.rl) {
            .ptr => .{ .ty = (try ri.rl.resultType(gz, block_node)).? },
            .inferred_ptr => .none,
            else => ri.rl,
        },
        .ctx = ri.ctx,
    };
    // We need to call `rvalue` to write through to the pointer only if we had a
    // result pointer and aren't forwarding it.
    const LocTag = @typeInfo(ResultInfo.Loc).@"union".tag_type.?;
    const need_result_rvalue = @as(LocTag, block_ri.rl) != @as(LocTag, ri.rl);

    // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
    // so that break statements can reference it.
    const block_inst = try gz.makeBlockInst(if (force_comptime) .block_comptime else .block, block_node);
    try gz.instructions.append(astgen.gpa, block_inst);
    var block_scope = gz.makeSubBlock(parent_scope);
    block_scope.is_inline = force_comptime;
    block_scope.label = GenZir.Label{
        .token = label_token,
        .block_inst = block_inst,
    };
    block_scope.setBreakResultInfo(block_ri);
    if (force_comptime) block_scope.is_comptime = true;
    defer block_scope.unstack();

    try blockExprStmts(&block_scope, &block_scope.base, statements, block_kind);
    if (!block_scope.endsWithNoReturn()) {
        // As our last action before the return, "pop" the error trace if needed
        _ = try gz.addRestoreErrRetIndex(.{ .block = block_inst }, .always, block_node);
        const result = try rvalue(gz, block_scope.break_result_info, .void_value, block_node);
        const break_tag: Zir.Inst.Tag = if (force_comptime) .break_inline else .@"break";
        _ = try block_scope.addBreak(break_tag, block_inst, result);
    }

    if (!block_scope.label.?.used) {
        try astgen.appendErrorTok(label_token, "unused block label", .{});
    }

    if (force_comptime) {
        try block_scope.setBlockComptimeBody(block_inst, .comptime_keyword);
    } else {
        try block_scope.setBlockBody(block_inst);
    }

    if (need_result_rvalue) {
        return rvalue(gz, ri, block_inst.toRef(), block_node);
    } else {
        return block_inst.toRef();
    }
}