What is the eval branch quota?

  1. What is the eval branch quota?
  2. Why does @setEvalBranchQuota() exist?
  3. If I exceed the eval branch quota, is this indicative of a bug in my library?
  4. Does setting the eval branch quota have effects on the users of my library?

The driver of this post is that after Sema: rewrite semantic analysis of function calls by mlugg · Pull Request #22414 · ziglang/zig · GitHub was merged I now exceed the eval branch quota and need to fix it.

What is the eval branch quota?

To prevent comptime code for evaluating forever, zig gives it a quota of how many iterations / branches it can evaluate at time.

Why does @setEvalBranchQuota() exist?

@setEvalBranchQuota can be used to modify the quota limit. Typically you want to calculate the required quota for your comptime function based on the inputs.

If I exceed the eval branch quota, is this indicative of a bug in my library?

If you were using constant quota, then not necessarily. If you calculated your quota, then your calculations might’ve been wrong. Sometimes implementations can change, and if you call into any of these changed implications, the amount of quota being used can fluctuate.

Does setting the eval branch quota have effects on the users of my library?

No, it is purely to limit comptime execution.

4 Likes

How do I calculate my expected usage of the eval branch quota?

For example if you would iterate a elements of slice, you would set the eval branch quota the length of the slice. Typically you want to multiply the estimated quota with some “good guess” number if you aren’t entirely sure about the costs of operations in the inner loop, this should keep your quotas somewhat constrained to the algorithm itself.

Simple example:

comptime {
	var i = 0;
    // without this: error: evaluation exceeded 1000 backwards branches
	@setEvalBranchQuota(1001);
	while (i < 1001) : (i += 1) {}
}
1 Like

There’s no good way to calculate it when you anything remotely complicated. A comptime map, for example, can potentially involve thousands of evals per lookup.

It’s perfectly okay to use a really big number like 200,000.

Calculating the eval quota in general is the same as the halting problem right?

1 Like

Only if the zig compiler has an infinitely long paper tape. Unfortunately, it’s finite so there is an upper bound.

1 Like

The halting problem is the reason the quota exists. The compiler has no way of knowing whether it’s stuck in an infinite loop or it’s performing computationally heavy work.

The default of 1000 is not anywhere near what’s needed in real world usage. Basically, you’re supposed to run into the error so you’d think about what a reasonable figure should be for the given context. As someone pointed out earlier on this forum, std.fmt.compilePrint () sets the limit to 200000. The default is very low because there’s no general reasonable figure.

1 Like