Skip to content

Commit

Permalink
Fixed bug that leads to a hang when returning a tuple from a lambda a…
Browse files Browse the repository at this point in the history
…rgument expression in certain circumstances. This addresses #9558 and #9536. (#9560)
  • Loading branch information
erictraut authored Dec 7, 2024
1 parent 89b78d3 commit 8fe87a9
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 0 deletions.
11 changes: 11 additions & 0 deletions packages/pyright-internal/src/analyzer/typeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ export interface AddConditionOptions {
skipBoundTypeVars?: boolean;
}

// There are cases where tuple types can be infinitely nested. The
// recursion count limit will eventually be hit, but this will create
// deep types that will effectively hang the analyzer. To prevent this,
// we'll limit the depth of the tuple type arguments. This value is
// large enough that we should never hit it in legitimate circumstances.
const maxTupleTypeArgRecursionDepth = 10;

// Tracks whether a function signature has been seen before within
// an expression. For example, in the expression "foo(foo, foo)", the
// signature for "foo" will be seen three times at three different
Expand Down Expand Up @@ -3654,6 +3661,10 @@ export class TypeVarTransformer {

// Handle tuples specially.
if (ClassType.isTupleClass(classType)) {
if (getContainerDepth(classType) > maxTupleTypeArgRecursionDepth) {
return classType;
}

if (classType.priv.tupleTypeArgs) {
newTupleTypeArgs = [];

Expand Down
11 changes: 11 additions & 0 deletions packages/pyright-internal/src/tests/samples/tuple19.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This sample tests a case where the constraint solver generates a very
# "deep" tuple type. Previously, this caused a hang in the evaluator.

from typing import Callable


def func1[T](c: Callable[[T], T]): ...


# This should generate an error, not hang.
func1(lambda v: (v, v))
6 changes: 6 additions & 0 deletions packages/pyright-internal/src/tests/typeEvaluator8.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,12 @@ test('Tuple18', () => {
TestUtils.validateResults(analysisResults, 2);
});

test('Tuple19', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['tuple19.py']);

TestUtils.validateResults(analysisResults, 1);
});

test('NamedTuple1', () => {
const analysisResults = TestUtils.typeAnalyzeSampleFiles(['namedTuple1.py']);

Expand Down

0 comments on commit 8fe87a9

Please sign in to comment.