Diagnostic and cause
LinkRecursion limit exceeded
- Family
- topaz
- Phase
- run
- Code
TPZ5009
Cause and conditions
Named program functions, lambdas, user callbacks, protocol methods, and receiver methods each count as one active call. Standard functions do not count. A user callback invoked by a standard function counts. A defer block does not add a call. A concurrent arm inherits the depth of the call that opened its group. Entering a counted call while 1000 calls are active produces TPZ5009 at the rejected call. An implementation must not exhaust its stack while fewer than 1000 counted calls are active.
Related rule: Counted calls and the runtime depth limitResponse
Check the base case and progress toward it. Rewrite deep recursion as a loop when the input can require many calls.
Source evidence
- compiler/crates/topaz_diag/src/explain.rs at
151141d7bb44· 678-687 - compiler/crates/topaz_product_runtime/src/diagnostic.rs at
151141d7bb44· 70-70 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56
Compiler phase: runtime.
Compiler explanation: Nested Topaz calls exceeded the shared call-depth limit.
Message templates are Pending. The explanation above is not an observed CLI message.
The program attempts to enter a counted call while 1000 counted calls are active.
Counted calls and the runtime depth limit
Named program functions, lambdas, user callbacks, protocol methods, and receiver methods each count as one active call. Standard functions do not count. A user callback invoked by a standard function counts. A defer block does not add a call. A concurrent arm inherits the depth of the call that opened its group. Entering a counted call while 1000 calls are active produces TPZ5009 at the rejected call. An implementation must not exhaust its stack while fewer than 1000 counted calls are active.
Why
The same program reaches the same call-depth diagnostic on every target. Host stack size must not cause an earlier failure.
Source evidence
- compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56
Response
LinkCheck the base case and progress toward it. Rewrite deep recursion as a loop when the input can require many calls.
Reproduction and verification
LinkRejected program
Linkfunction descend(depth: int) -> int {if (depth == 0) {0} else {descend(depth - 1)}}let result = descend(1001)
No stdout.
Expected result
Run the named-function and lambda runtime examples with TOPAZ_BIN set using node docs/topaz-reference/templates/diagnostics-p5-runtime.product.mjs.
Source evidence
- compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56
Repaired program
Linkfunction descend(depth: int) -> int {if (depth == 0) {0} else {descend(depth - 1)}}let result = descend(10)
No stdout.
Expected result
Expected result
Execution completes. Exit code 0.
Run the named-function and lambda runtime examples with TOPAZ_BIN set using node docs/topaz-reference/templates/diagnostics-p5-runtime.product.mjs.
Source evidence
- compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56
A recursive lambda reaches the same call limit
Linkimport std.iolet mut descend: (int) -> int = (depth) => 0descend = (depth) => {if (depth == 0) {0} else {descend(depth - 1)}}let result = descend(1001)io.writeLine("{result}")
No stdout.
Expected result
Run the named-function and lambda runtime examples with TOPAZ_BIN set using node docs/topaz-reference/templates/diagnostics-p5-runtime.product.mjs.
Source evidence
- compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56
A recursive lambda finishes below the call limit
Linkimport std.iolet mut descend: (int) -> int = (depth) => 0descend = (depth) => {if (depth == 0) {0} else {descend(depth - 1)}}let result = descend(10)io.writeLine("{result}")
0
Expected result
Expected result
Execution completes. Exit code 0.
0
Run the named-function and lambda runtime examples with TOPAZ_BIN set using node docs/topaz-reference/templates/diagnostics-p5-runtime.product.mjs.
Source evidence
- compiler/crates/topaz_value/src/value/model.rs at
151141d7bb44· 13-31 - compiler/crates/topaz_product_runtime/src/runtime/machine.rs at
151141d7bb44· 484-499 - compiler/crates/topaz_product_runtime/src/runtime/call.rs at
151141d7bb44· 720-739 - compiler/crates/topaz_product_runtime/src/wire.rs at
151141d7bb44· 42-49 - compiler/crates/topaz_diag/src/code.rs at
151141d7bb44· 100-113 - compiler/crates/topaz_value/src/lib.rs at
151141d7bb44· 174-184 - issues/31 at
1cbf38d3d422 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 25-50 - compiler/crates/topaz_rt/src/closure.rs at
1cbf38d3d422· 664-687 - compiler/crates/topaz_rt/src/concurrent.rs at
1cbf38d3d422· 40-102 - compiler/crates/topaz_rt/src/defer.rs at
1cbf38d3d422· 47-56