microsoft / pyright

Static Type Checker for Python
Other
13.28k stars 1.44k forks source link

RangeError: Maximum call stack size exceeded #9283

Open Darxor opened 1 day ago

Darxor commented 1 day ago

Hello!

I am getting a Maximum call stack size exceeded when using rather a simple script with xlsxwriter.

Here is reproducible minimal example (callstack-error.py)

from xlsxwriter import Workbook

def foo(wb: Workbook) -> None:
    wb = Workbook("temp.xlsx")
    ws = wb.add_worksheet()
    ws.write(
        0, 0, "Hello, world!"
    )

Running pyright callstack-error.py in terminal yields An internal error occurred while type checking file "[...]/callstack-error.py": RangeError: Maximum call stack size exceeded.

I am running Python v3.12.7 under MacOS Sequoia 15.0.1, on M1 Pro My venv (uv pip freeze output):

nodeenv==1.9.1
pyright==1.1.385
typing-extensions==4.12.2
xlsxwriter==3.2.0

I have tried to run pyright directly on xlsxwriter (by copying it from .venv and running pyright xlsxwriter), which yields expected results with errors, warnings etc. and leads me to believe error does not lie in xlsxwriter itself.

Full traceback ``` An internal error occurred while type checking file "/Users/darx/Documents/Hobby/pyright-callstack-repro/callstack-error.py": RangeError: Maximum call stack size exceeded at Object.getParamType (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/types.ts:2262:21) at addVirtualParam (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:150:52) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:299:13) at Array.forEach () at getParamListDetails (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:158:28) at matchArgsToParams (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:10420:30) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9289:38) at Array.forEach () at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9285:47) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21314:28) at validateOverloadedArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9283:9) at validateCallForOverloaded (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9921:28) at validateCallArgsForSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9659:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9566:44) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21308:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9563:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4106:43) at doForEachSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeUtils.ts:765:9) at expandSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4090:13) at mapSubtypesExpandTypeVars (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4148:13) at validateCallArgs (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9559:26) at getTypeOfCall (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8268:36) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:62) at useSignatureTracker (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21267:28) at getTypeOfExpressionCore (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:30) at getTypeOfExpression (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1119:26) at evaluateTypesForAssignmentStatement (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:16564:35) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20182:25) at a.evaluateTypesForStatement [as timeOperation] (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/common/timing.ts:40:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:438:31) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20308:9) at a.evaluateTypeForSubnode [as timeOperation] (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/common/timing.ts:40:20) at evaluateAssignmentFlowNode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:437:34) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:555:37) at preventRecursion (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:446:36) at getTypeFromFlowNode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:554:54) at Object.getTypeFromCodeFlow (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:1229:20) at getFlowTypeOfReference (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20395:25) at getTypeOfName (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4665:44) at getTypeOfExpressionCore (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1204:30) at getTypeOfExpression (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1119:26) at validateArgType (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:12227:40) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11750:31) at Array.forEach () at validateArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11749:32) at validateArgTypesWithContext (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11570:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8990:28) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21314:28) at validateOverloadsWithExpandedTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8989:36) at validateOverloadedArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9400:32) at validateCallForOverloaded (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9921:28) at validateCallArgsForSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9659:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9566:44) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21308:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9563:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4106:43) at doForEachSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeUtils.ts:765:9) at expandSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4090:13) at mapSubtypesExpandTypeVars (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4148:13) at validateCallArgs (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9559:26) at getTypeOfCall (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8268:36) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:62) at useSignatureTracker (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21267:28) at /Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:30 Error performing analysis: RangeError: Maximum call stack size exceeded at Object.getParamType (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/types.ts:2262:21) at addVirtualParam (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:150:52) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:299:13) at Array.forEach () at getParamListDetails (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/parameterUtils.ts:158:28) at matchArgsToParams (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:10420:30) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9289:38) at Array.forEach () at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9285:47) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21314:28) at validateOverloadedArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9283:9) at validateCallForOverloaded (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9921:28) at validateCallArgsForSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9659:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9566:44) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21308:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9563:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4106:43) at doForEachSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeUtils.ts:765:9) at expandSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4090:13) at mapSubtypesExpandTypeVars (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4148:13) at validateCallArgs (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9559:26) at getTypeOfCall (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8268:36) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:62) at useSignatureTracker (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21267:28) at getTypeOfExpressionCore (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:30) at getTypeOfExpression (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1119:26) at evaluateTypesForAssignmentStatement (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:16564:35) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20182:25) at a.evaluateTypesForStatement [as timeOperation] (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/common/timing.ts:40:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:438:31) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20308:9) at a.evaluateTypeForSubnode [as timeOperation] (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/common/timing.ts:40:20) at evaluateAssignmentFlowNode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:437:34) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:555:37) at preventRecursion (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:446:36) at getTypeFromFlowNode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:554:54) at Object.getTypeFromCodeFlow (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/codeFlowEngine.ts:1229:20) at getFlowTypeOfReference (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:20395:25) at getTypeOfName (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4665:44) at getTypeOfExpressionCore (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1204:30) at getTypeOfExpression (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1119:26) at validateArgType (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:12227:40) at forEach (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11750:31) at Array.forEach () at validateArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11749:32) at validateArgTypesWithContext (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:11570:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8990:28) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21314:28) at validateOverloadsWithExpandedTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8989:36) at validateOverloadedArgTypes (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9400:32) at validateCallForOverloaded (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9921:28) at validateCallArgsForSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9659:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9566:44) at useSpeculativeMode (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21308:20) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9563:24) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4106:43) at doForEachSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeUtils.ts:765:9) at expandSubtype (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4090:13) at mapSubtypesExpandTypeVars (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:4148:13) at validateCallArgs (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:9559:26) at getTypeOfCall (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:8268:36) at callback (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:62) at useSignatureTracker (/Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:21267:28) at /Users/darx/.cache/pyright-python/1.1.385/node_modules/pyright/dist/pyright-internal/src/analyzer/typeEvaluator.ts:1219:30 ```
erictraut commented 1 day ago

This error message is typically caused by a bug in pyright's logic that leads to infinite recursion. In this case, it's not infinite recursion but rather very deep recursion that occurs when analyzing code with a very long chain of dependent function calls. In particular, the problem occurs when pyright attempts to infer the return type for the Worksheet._prepare_formula method. Inference is required here because the method has no return type annotation. To infer the return type, pyright must evaluate the types of all values returned via return statements. The final statement is a return formula statement. To evaluate the type of formula, pyright must evaluate the return type of the call to re.sub, but this requires knowing the type of the argument formula, which requires evaluating another call to re.sub, etc. To make matters more difficult, re.sub is an overloaded function, so evaluating this call is more complex and requires more stack frames than a normal (non-overloaded) function. The result is that pyright gets several thousand stack frames into its evaluation and then exhausts the stack.

I don't recall ever seeing this limit reached before. I'll need to think about whether there are ways to detect and mitigate the problem before it results in a crash.

I suspect the reason that we haven't seen this before is that code typically isn't written with "unrolled" function calls in this manner. More typically, this would be done with a loop that acts upon some iterable data structure.

erictraut commented 12 hours ago

After further investigation, I don't see a great solution here. There's no good way for pyright's logic to detect this case prior to the crash. It would involve manually tracking the call depth during analysis or use introspection routines to determine the depth of the stack. And even if this condition could be detected in a reasonable way, there's no good way to handle the condition. It would result in inconsistent and nondeterministic type evaluation behaviors, which we try to avoid. It would allow us to give the user a more meaningful error message, but it wouldn't solve the problem they're encountering.

I don't see a way to detect this situation in the binder, where we currently detect functions with high cyclomatic complexity. This condition doesn't involve cycles or complex code flow graphs, so we can't use the trick where we refrain from performing code flow analysis on complex functions. This condition can be detected only at code flow analysis time.

Each stacked call to re.sub in this code sample consumes 36 frames on the stack, and many of these calls involve a large number of local variables. After about 148 stacked (dependent) calls, we hit the 1MB stack limit, which is the default for node.

One solution is to increase node's max stack size. If I double the default from 1MB to 2MB, this crash no longer occurs. It is still theoretically possible to create a source file that exhausts the stack, but it makes this condition less likely. This solution consumes an additional 1MB of memory for all pyright and pylance users, so we'd need to decide whether that's a good tradeoff.

@debonte, @rchiodo, are you seeing signal from pylance telemetry that this is a common source of crashes? What do you think about increasing the default stack size? I can easily make this change in the pyright language client (in the extension.ts module), but I don't know if you have the ability to control this in pylance since it doesn't have its own language client component. Do you have any ideas for other potential solutions?