Fix hang in constraint solver for cyclic TypeVar lower bounds (#11413)#11415
Conversation
…oft#11413) When the constraint solver established a TypeVar's first lower bound, it would unconditionally record the source type even when that source type contained the destination TypeVar nested inside another generic constructor (e.g. R := R | Awaitable[R], as produced when matching wrapt 2.1.x's wrap_function_wrapper against a generic make_wrapper). Each subsequent round of solveAndApplyConstraints substituted R with its own ever-growing bound, producing exponentially larger types and hanging the analyzer. Add an occurs check in assignUnconstrainedTypeVar: if adjSrcType references destType at a strictly nested position, refuse the assignment rather than recording a non-finitely-solvable constraint. Top-level union members that are exactly the TypeVar (e.g. T := T | int from protocol matching against T | int) are explicitly allowed and resolved by the existing logic. Adds a regression test (paramSpec56) that hangs without the fix and completes in ~640ms with it.
|
Diff from mypy_primer, showing the effect of this PR on open source code: sympy (https://github.com/sympy/sympy)
+ .../projects/sympy/sympy/integrals/integrals.py:107:41 - error: Argument of type "list[tuple[_T_co@tuple, ...]]" cannot be assigned to parameter "iterable" of type "Iterable[_T_co@tuple]" in function "__new__" (reportArgumentType)
- "FunctionType" is not assignable to "PlotInterval" (reportArgumentType)
+ Type "(self: Self@PlotInterval) -> (Any | Unknown)" is not assignable to type "Self@PlotInterval" (reportArgumentType)
- "FunctionType" is not assignable to "PlotInterval" (reportArgumentType)
+ Type "(self: Self@PlotInterval) -> None" is not assignable to type "Self@PlotInterval" (reportArgumentType)
- "FunctionType" is not assignable to "PlotInterval" (reportArgumentType)
+ Type "(self: Self@PlotInterval) -> Generator[Any | Unknown, Any, None]" is not assignable to type "Self@PlotInterval" (reportArgumentType)
- "FunctionType" is not assignable to "PlotInterval" (reportArgumentType)
+ Type "(self: Self@PlotInterval) -> Generator[tuple[Any | Unknown, Any | Unknown], Any, None]" is not assignable to type "Self@PlotInterval" (reportArgumentType)
- "FunctionType" is not assignable to "PlotModeBase" (reportArgumentType)
+ Type "(self: Self@PlotModeBase, function: Unknown) -> None" is not assignable to type "Self@PlotModeBase" (reportArgumentType)
- "FunctionType" is not assignable to "PlotModeBase" (reportArgumentType)
+ Type "(self: Self@PlotModeBase, function: Unknown) -> None" is not assignable to type "Self@PlotModeBase" (reportArgumentType)
- "FunctionType" is not assignable to "PlotModeBase" (reportArgumentType)
+ Type "(self: Self@PlotModeBase) -> None" is not assignable to type "Self@PlotModeBase" (reportArgumentType)
- "FunctionType" is not assignable to "PlotModeBase" (reportArgumentType)
+ Type "(self: Self@PlotModeBase, v: Unknown) -> None" is not assignable to type "Self@PlotModeBase" (reportArgumentType)
- "FunctionType" is not assignable to "PlotModeBase" (reportArgumentType)
+ Type "(self: Self@PlotModeBase, v: Unknown) -> None" is not assignable to type "Self@PlotModeBase" (reportArgumentType)
+ .../projects/sympy/sympy/polys/rings.py:852:34 - error: Type "PolyElement[Er@PolyElement]" cannot be assigned to type variable "Er@PolyElement"
+ Type "PolyElement[Er@PolyElement]" is not assignable to upper bound "RingElement" for type variable "Er@PolyElement"
+ "PolyElement[Er@PolyElement]" is incompatible with protocol "RingElement"
+ "__add__" is an incompatible type
+ Type "(other: PolyElement[Er@PolyElement] | Er@PolyElement | int | PolyElement[PolyElement[Er@PolyElement]], /) -> (PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]])" is not assignable to type "(other: PolyElement[Er@PolyElement] | int, /) -> PolyElement[Er@PolyElement]"
+ Function return type "PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]]" is incompatible with type "PolyElement[Er@PolyElement]" (reportInvalidTypeArguments)
+ .../projects/sympy/sympy/polys/rings.py:853:22 - error: Type "PolyElement[Er@PolyElement]" cannot be assigned to type variable "Er@PolyElement"
+ Type "PolyElement[Er@PolyElement]" is not assignable to upper bound "RingElement" for type variable "Er@PolyElement"
+ "PolyElement[Er@PolyElement]" is incompatible with protocol "RingElement"
+ "__add__" is an incompatible type
+ Type "(other: PolyElement[Er@PolyElement] | Er@PolyElement | int | PolyElement[PolyElement[Er@PolyElement]], /) -> (PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]])" is not assignable to type "(other: PolyElement[Er@PolyElement] | int, /) -> PolyElement[Er@PolyElement]"
+ Function return type "PolyElement[Er@PolyElement] | PolyElement[PolyElement[Er@PolyElement]]" is incompatible with type "PolyElement[Er@PolyElement]" (reportInvalidTypeArguments)
- .../projects/sympy/sympy/solvers/tests/test_solvers.py:1214:18 - error: Operator "+" not supported for types "Basic" and "Expr" (reportOperatorIssue)
- .../projects/sympy/sympy/solvers/tests/test_solveset.py:445:30 - error: Cannot access attribute "limit_denominator" for class "NaN"
- Attribute "limit_denominator" is unknown (reportAttributeAccessIssue)
- .../projects/sympy/sympy/solvers/tests/test_solveset.py:445:30 - error: Cannot access attribute "limit_denominator" for class "ComplexInfinity"
- Attribute "limit_denominator" is unknown (reportAttributeAccessIssue)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:315:25 - error: "Set" is not iterable
+ "__iter__" method not defined (reportGeneralTypeIssues)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:315:25 - error: "ConditionSet" is not iterable
+ "__iter__" method not defined (reportGeneralTypeIssues)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2024:20 - error: "__getitem__" method not defined on type "Basic" (reportIndexIssue)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2036:20 - error: "__getitem__" method not defined on type "Basic" (reportIndexIssue)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2049:20 - error: "__getitem__" method not defined on type "Basic" (reportIndexIssue)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2070:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2071:20 - error: "__getitem__" method not defined on type "Basic" (reportIndexIssue)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2252:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2333:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2346:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2352:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2519:16 - error: Argument of type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | FiniteSet | Set | Intersection | Union | Complement | Any | ConditionSet" is not assignable to type "Sized"
+ "Set" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
+ .../projects/sympy/sympy/solvers/tests/test_solveset.py:2522:20 - error: Argument of type "Unknown | Basic | Any" cannot be assigned to parameter "obj" of type "Sized" in function "len"
+ Type "Unknown | Basic | Any" is not assignable to type "Sized"
+ "Basic" is incompatible with protocol "Sized"
+ "__len__" is not present (reportArgumentType)
- .../projects/sympy/sympy/stats/crv_types.py:2544:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
- Return type mismatch: base method returns type "None", override returns type "ComplexInfinity | NaN | Rational | Unknown | Zero | Expr"
- Type "ComplexInfinity | NaN | Rational | Unknown | Zero | Expr" is not assignable to type "None"
- "Expr" is not assignable to "None" (reportIncompatibleMethodOverride)
- .../projects/sympy/sympy/stats/crv_types.py:2723:9 - error: Method "_cdf" overrides class "SingleContinuousDistribution" in an incompatible manner
- Return type mismatch: base method returns type "None", override returns type "Expr | NaN | ComplexInfinity | Rational | Unknown | One | NegativeOne | Zero | Integer"
- Type "Expr | NaN | ComplexInfinity | Rational | Unknown | One | NegativeOne | Zero | Integer" is not assignable to type "None"
- "Expr" is not assignable to "None" (reportIncompatibleMethodOverride)
... (truncated 773 lines) ...
prefect (https://github.com/PrefectHQ/prefect)
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py:149:15 - error: Method "wait_for_call_in_new_thread" overrides class "_base" in an incompatible manner
+ Parameter 1 type mismatch: base parameter is type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread] | Call[T@wait_for_call_in_new_thread]", override parameter is type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ Return type mismatch: base method returns type "T@wait_for_call_in_new_thread", override returns type "CoroutineType[Any, Any, T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread] | Call[T@wait_for_call_in_new_thread]" is not assignable to type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread]" is not assignable to type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ "FunctionType" is not assignable to "Call[T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread]" is not assignable to type "() -> T@wait_for_call_in_new_thread"
+ Function return type "T@wait_for_call_in_new_thread | Awaitable[T@wait_for_call_in_new_thread]" is incompatible with type "T@wait_for_call_in_new_thread"
+ Type "CoroutineType[Any, Any, T@wait_for_call_in_new_thread]" is not assignable to type "T@wait_for_call_in_new_thread" (reportIncompatibleMethodOverride)
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py:163:9 - error: Method "call_in_new_thread" overrides class "_base" in an incompatible manner
+ Return type mismatch: base method returns type "T@call_in_new_thread", override returns type "Awaitable[T@call_in_new_thread]"
+ Type "Awaitable[T@call_in_new_thread]" is not assignable to type "T@call_in_new_thread" (reportIncompatibleMethodOverride)
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py:170:9 - error: Method "call_in_loop_thread" overrides class "_base" in an incompatible manner
+ Return type mismatch: base method returns type "T@call_in_loop_thread", override returns type "Awaitable[T@call_in_loop_thread]"
+ Type "Awaitable[T@call_in_loop_thread]" is not assignable to type "T@call_in_loop_thread" (reportIncompatibleMethodOverride)
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py:201:9 - error: Method "wait_for_call_in_new_thread" overrides class "_base" in an incompatible manner
+ Parameter 1 type mismatch: base parameter is type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread] | Call[T@wait_for_call_in_new_thread]", override parameter is type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread] | Call[T@wait_for_call_in_new_thread]" is not assignable to type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread]" is not assignable to type "(() -> T@wait_for_call_in_new_thread) | Call[T@wait_for_call_in_new_thread]"
+ "FunctionType" is not assignable to "Call[T@wait_for_call_in_new_thread]"
+ Type "_SyncOrAsyncCallable[(), T@wait_for_call_in_new_thread]" is not assignable to type "() -> T@wait_for_call_in_new_thread"
+ Function return type "T@wait_for_call_in_new_thread | Awaitable[T@wait_for_call_in_new_thread]" is incompatible with type "T@wait_for_call_in_new_thread" (reportIncompatibleMethodOverride)
+ .../projects/prefect/src/prefect/_internal/concurrency/api.py:223:9 - error: Method "call_in_loop_thread" overrides class "_base" in an incompatible manner
+ Return type mismatch: base method returns type "T@call_in_loop_thread", override returns type "Awaitable[T@call_in_loop_thread] | T@call_in_loop_thread"
+ Type "Awaitable[T@call_in_loop_thread] | T@call_in_loop_thread" is not assignable to type "T@call_in_loop_thread" (reportIncompatibleMethodOverride)
- 6223 errors, 184 warnings, 0 informations
+ 6228 errors, 184 warnings, 0 informations
core (https://github.com/home-assistant/core)
+ Type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job] | _R@async_add_hass_job], *args: Any, eager_start: bool = False, background: bool = False) -> (Future[_R@async_add_hass_job] | None)" is not assignable to type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job]], *args: Any, eager_start: bool = False, background: bool = False) -> (Future[_R@async_add_hass_job] | None)"
+ Parameter 2: type "HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job]]" is incompatible with type "HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job] | _R@async_add_hass_job]"
+ "HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job]]" is not assignable to "HassJob[..., Coroutine[Any, Any, _R@async_add_hass_job] | _R@async_add_hass_job]"
+ Type parameter "_R_co@HassJob" is invariant, but "Coroutine[Any, Any, _R@async_add_hass_job]" is not the same as "Coroutine[Any, Any, _R@async_add_hass_job] | _R@async_add_hass_job" (reportInconsistentOverload)
- Function return type "Future[Coroutine[Any, Any, _R@async_add_hass_job]] | None" is incompatible with type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_add_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@async_add_hass_job]] | None" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_add_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@async_add_hass_job]]" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_add_hass_job]]]]] | None"
- "Future[Coroutine[Any, Any, _R@async_add_hass_job]]" is not assignable to "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_add_hass_job]]]]]"
- Type parameter "_T@Future" is invariant, but "Coroutine[Any, Any, _R@async_add_hass_job]" is not the same as "Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_add_hass_job]]]]"
- "Future[Coroutine[Any, Any, _R@async_add_hass_job]]" is not assignable to "None" (reportInconsistentOverload)
+ Type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job] | _R@_async_add_hass_job], *args: Any, background: bool = False) -> (Future[_R@_async_add_hass_job] | None)" is not assignable to type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job]], *args: Any, background: bool = False) -> (Future[_R@_async_add_hass_job] | None)"
+ Parameter 2: type "HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job]]" is incompatible with type "HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job] | _R@_async_add_hass_job]"
+ "HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job]]" is not assignable to "HassJob[..., Coroutine[Any, Any, _R@_async_add_hass_job] | _R@_async_add_hass_job]"
+ Type parameter "_R_co@HassJob" is invariant, but "Coroutine[Any, Any, _R@_async_add_hass_job]" is not the same as "Coroutine[Any, Any, _R@_async_add_hass_job] | _R@_async_add_hass_job" (reportInconsistentOverload)
- Function return type "Future[Coroutine[Any, Any, _R@_async_add_hass_job]] | None" is incompatible with type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@_async_add_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@_async_add_hass_job]] | None" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@_async_add_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@_async_add_hass_job]]" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@_async_add_hass_job]]]]] | None"
- "Future[Coroutine[Any, Any, _R@_async_add_hass_job]]" is not assignable to "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@_async_add_hass_job]]]]]"
- Type parameter "_T@Future" is invariant, but "Coroutine[Any, Any, _R@_async_add_hass_job]" is not the same as "Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@_async_add_hass_job]]]]"
- "Future[Coroutine[Any, Any, _R@_async_add_hass_job]]" is not assignable to "None" (reportInconsistentOverload)
+ Type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job] | _R@async_run_hass_job], *args: Any, background: bool = False) -> (Future[_R@async_run_hass_job] | None)" is not assignable to type "(self: Self@HomeAssistant, hassjob: HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job]], *args: Any, background: bool = False) -> (Future[_R@async_run_hass_job] | None)"
+ Parameter 2: type "HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job]]" is incompatible with type "HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job] | _R@async_run_hass_job]"
+ "HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job]]" is not assignable to "HassJob[..., Coroutine[Any, Any, _R@async_run_hass_job] | _R@async_run_hass_job]"
+ Type parameter "_R_co@HassJob" is invariant, but "Coroutine[Any, Any, _R@async_run_hass_job]" is not the same as "Coroutine[Any, Any, _R@async_run_hass_job] | _R@async_run_hass_job" (reportInconsistentOverload)
- Function return type "Future[Coroutine[Any, Any, _R@async_run_hass_job]] | None" is incompatible with type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_run_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@async_run_hass_job]] | None" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_run_hass_job]]]]] | None"
- Type "Future[Coroutine[Any, Any, _R@async_run_hass_job]]" is not assignable to type "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_run_hass_job]]]]] | None"
- "Future[Coroutine[Any, Any, _R@async_run_hass_job]]" is not assignable to "Future[Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_run_hass_job]]]]]"
- Type parameter "_T@Future" is invariant, but "Coroutine[Any, Any, _R@async_run_hass_job]" is not the same as "Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, Coroutine[Any, Any, _R@async_run_hass_job]]]]"
- "Future[Coroutine[Any, Any, _R@async_run_hass_job]]" is not assignable to "None" (reportInconsistentOverload)
xarray (https://github.com/pydata/xarray)
+ .../projects/xarray/xarray/backends/netCDF4_.py:439:13 - error: Argument of type "DummyFileManager[Unknown] | Unknown" cannot be assigned to parameter "manager" of type "Unknown" in function "__init__"
+ Type "DummyFileManager[Unknown] | Unknown" is not assignable to type "Unknown" (reportArgumentType)
- 2359 errors, 201 warnings, 0 informations
+ 2360 errors, 201 warnings, 0 informations
jax (https://github.com/google/jax)
+ .../projects/jax/jax/_src/checkify.py:133:7 - error: Method "tree_flatten" overrides class "JaxException" in an incompatible manner
+ Return type mismatch: base method returns type "tuple[list[Unknown], Unknown]", override returns type "tuple[list[Unknown], tuple[Unknown, Unknown]]"
+ "tuple[list[Unknown], tuple[Unknown, Unknown]]" is not assignable to "tuple[list[Unknown], Unknown]"
+ Tuple entry 2 is incorrect type
+ Type "tuple[Unknown, Unknown]" is not assignable to type "Unknown" (reportIncompatibleMethodOverride)
+ .../projects/jax/jax/_src/checkify.py:155:7 - error: Method "tree_flatten" overrides class "JaxException" in an incompatible manner
+ Return type mismatch: base method returns type "tuple[list[Unknown], Unknown]", override returns type "tuple[list[Unknown], tuple[Unknown, Unknown, Unknown]]"
+ "tuple[list[Unknown], tuple[Unknown, Unknown, Unknown]]" is not assignable to "tuple[list[Unknown], Unknown]"
+ Tuple entry 2 is incorrect type
+ Type "tuple[Unknown, Unknown, Unknown]" is not assignable to type "Unknown" (reportIncompatibleMethodOverride)
- 3288 errors, 92 warnings, 0 informations
+ 3290 errors, 92 warnings, 0 informations
|
mypy_primer analysisI went through every diff. Summary: all the changes are either correct improvements or genuine bugs that the cycle was previously masking. Net +8 errors across 5 projects, but those errors are real, and many of the "removed" errors were false positives. Several remaining errors also became dramatically more readable. home-assistant/core — improvement (no count change)All This is exactly the cyclic-explosion this PR is fixing — the constraint solver was repeatedly substituting sympy — mostly correctRemoved (false positives):
New (genuine):
Improved messages (no count change):
prefect — genuine bugs uncovered (+5 errors)All five new errors are in These are genuine override mismatches: the base class declares jax — genuine bugs uncovered (+2 errors)
xarray — minor, arguably correct (+1 error)
Bottom line
I don't think any of these warrant a fix on this PR — the new errors are correct, the removed errors were false positives, and the improved messages are a nice bonus. |
Summary
Fixes #11413.
Pyright would hang indefinitely while analyzing code that combined wrapt 2.1.x's
wrap_function_wrapperwith a genericmake_wrapperfactory whose return type was a union containing bothRandAwaitable[R]. The user-reported repro is at https://github.com/Gatedd/pyright-minimal-repo.Root cause
In
assignUnconstrainedTypeVar(packages/pyright-internal/src/analyzer/constraintSolver.ts), when a TypeVar's first lower bound was being established, the source type was recorded unconditionally — even when that source type contained the destination TypeVar nested inside another generic constructor.For the wrapt case the constraint solver received:
There is no finite type that satisfies this. Each subsequent round of
solveAndApplyConstraintssubstitutedRwith its own ever-growing bound, producing types of the form:The recursion-depth cap (20) was hit per call, but the per-call combinatorial work grew exponentially, producing a hang rather than a clean infinite loop.
Fix
Add a classical occurs check before recording the lower bound. If
adjSrcTypereferencesdestTypeat a strictly nested position (e.g.R := F[R]orR := R | Awaitable[R]), refuse the assignment and returnfalse.The check is carefully scoped to allow two benign shapes that the existing logic already handles correctly:
T := T) — fine, it's the identity constraint.T := T | int, which arises naturally from protocol matching against a method returningT | int) — also fine; the existing solver resolves it. This is exercised by the existingProtocol44test.Only strictly nested references trigger the failure path.
Test
Adds
paramSpec56regression sample + test. Without the fix the test hangs the jest worker (SIGTERM after timeout); with the fix analysis completes in ~640ms.Verification
typeEvaluator*andcheckertests pass locally.Tuple19(similar cyclic shape, surfaces an error via Eric's earlier tuple-depth cap),Protocol44(legitimateT | intshape), all 56 otherParamSpec*tests.Caveat
For the wrapt case the constraint solver detects the cycle and refuses to bind the TypeVar, but the failure isn't surfaced as a user-visible diagnostic in this particular path — it occurs deep inside bidirectional inference for an argument expression where the diag isn't threaded through. The user's original code is type-incorrect, but pyright won't currently flag it; the important behavioral change here is that analysis completes instead of hanging. Threading a diagnostic through that call site would be a separate improvement.