Hitting comptime limit for unclear reasons and `setEvalBranchQuota` doesn't make it go away

Hello

So I am hitting this error:

src/tag_table.zig:634:41: error: evaluation exceeded 1000 backwards branches

Putting this in main doesn’t remove the error nor change the 1000 number in the error

@setEvalBranchQuota(std.math.maxInt(u32));

I can’t figure out what’s even being run in comptime or why is it hitting it, and not sure how to debug it.

The error is being hit in the middle of a 1600 item list (generated).

pub const OPEN_TYPE_LANGUAGES: []const LangTag = &.{
    .{ .language = "aa", .tag = .from_bytes("AFR ") }, // Afar
    .{ .language = "aae", .tag = .from_bytes("SQI ") }, // Arbëreshë Albanian -> Albanian
     // goes on ..
}

This is from_bytes

    pub fn from_bytes(bytes: *const [4]u8) Tag {
        return .{ .inner = std.mem.readInt(u32, bytes, .big) };
    }

Try putting it in a block:

pub const OPEN_TYPE_LANGUAGES: []const LangTag = init: {
    @setEvalBranchQuota(2_000_000_000);
    break :init &.{
        .{ .language = "aa", .tag = .from_bytes("AFR ") }, // Afar
        .{ .language = "aae", .tag = .from_bytes("SQI ") }, // Arbëreshë Albanian -> Albanian
         // goes on ..
    };
};
1 Like

Thanks. This does make it go away. I thought the eval quota was global, tho?

It only applies to the current and child scopes, it does not propagate through functions.

I could be wrong, I am going off of memory and the lang ref provides no useful information.

1 Like

It didn’t work in your case because the OPEN_TYPE_LANGUAGES initialisation was at the file root level.
If you just put @setEvalBranchQuota() in a comptime block at the file root, it essentially doesn’t do anything; it won’t affect any of the initialisations in the file, because they’re not in that block.
Which is why putting the initialisation in a block is neccessary for @setEvalBranchQuota() to work on it.

1 Like

I don’t think it does. From Sema.zig, specifically the part responsible for handling updating the eval branch quota:

fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
    const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
    const src = block.nodeOffset(inst_data.src_node);
    const quota: u32 = @intCast(try sema.resolveInt(block, src, inst_data.operand, .u32, .{ .simple = .operand_setEvalBranchQuota }));
    sema.branch_quota = @max(sema.branch_quota, quota);
    sema.allow_memoize = false;
}

This appears to sets branch quota on the sema object itself, which as the doc comment at the top of the file notes is shared between every block:

//! Semantic analysis of ZIR instructions.
//! Shared to every Block. Stored on the stack.
//! State used for compiling a ZIR into AIR.
//! Transforms untyped ZIR instructions into semantically-analyzed AIR instructions.
//! Does type checking, comptime control flow, and safety-check generation.
//! This is the the heart of the Zig compiler.

My reading is that this applies to anything semantically analyzed after the @setEvalBranchQuota call. So it’s guaranteed to apply to the rest of the current scope, and any child scopes, but may also apply elsewhere depending on top-level evaluation order.

I’m not particularly familiar with the compiler internals, so I could be wrong.

1 Like