Commit ab88165326

Andrew Kelley <andrew@ziglang.org>
2022-05-26 02:27:21
Sema: generic function instantiations inherit branch quota
1 parent 1dd7109
Changed files (3)
src
test
behavior
src/Module.zig
@@ -1476,6 +1476,10 @@ pub const Fn = struct {
     lbrace_column: u16,
     rbrace_column: u16,
 
+    /// When a generic function is instantiated, this value is inherited from the
+    /// active Sema context. Importantly, this value is also updated when an existing
+    /// generic function instantiation is found and called.
+    branch_quota: u32,
     state: Analysis,
     is_cold: bool = false,
     is_noinline: bool = false,
@@ -4891,6 +4895,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
         .func = func,
         .fn_ret_ty = decl.ty.fnReturnType(),
         .owner_func = func,
+        .branch_quota = @maximum(func.branch_quota, Sema.default_branch_quota),
     };
     defer sema.deinit();
 
src/Sema.zig
@@ -38,7 +38,7 @@ func: ?*Module.Fn,
 /// generic function which uses a type expression for the return type.
 /// The type will be `void` in the case that `func` is `null`.
 fn_ret_ty: Type,
-branch_quota: u32 = 1000,
+branch_quota: u32 = default_branch_quota,
 branch_count: u32 = 0,
 /// Populated when returning `error.ComptimeBreak`. Used to communicate the
 /// break instruction up the stack to find the corresponding Block.
@@ -102,6 +102,8 @@ const Package = @import("Package.zig");
 const crash_report = @import("crash_report.zig");
 const build_options = @import("build_options");
 
+pub const default_branch_quota = 1000;
+
 pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
 
 /// This is the context needed to semantically analyze ZIR instructions and
@@ -3752,8 +3754,7 @@ fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
     const src = inst_data.src();
     const quota = @intCast(u32, try sema.resolveInt(block, src, inst_data.operand, Type.u32));
-    if (sema.branch_quota < quota)
-        sema.branch_quota = quota;
+    sema.branch_quota = @maximum(sema.branch_quota, quota);
 }
 
 fn zirStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -5679,6 +5680,8 @@ fn instantiateGenericCall(
         break :callee new_func;
     } else gop.key_ptr.*;
 
+    callee.branch_quota = @maximum(callee.branch_quota, sema.branch_quota);
+
     const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
 
     // Make a runtime call to the new function, making sure to omit the comptime args.
@@ -6773,6 +6776,7 @@ fn funcCommon(
         .lbrace_column = @truncate(u16, src_locs.columns),
         .rbrace_column = @truncate(u16, src_locs.columns >> 16),
         .param_names = param_names,
+        .branch_quota = default_branch_quota,
     };
     if (maybe_inferred_error_set_node) |node| {
         new_func.inferred_error_sets.prepend(node);
test/behavior/eval.zig
@@ -704,8 +704,6 @@ test "call method with comptime pass-by-non-copying-value self parameter" {
 }
 
 test "setting backward branch quota just before a generic fn call" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     @setEvalBranchQuota(1001);
     loopNTimes(1001);
 }